Motivation

BMI is used as a proxy for adiposity and is measured as an individual’s weight in kilograms divided by the individual’s height in meters squared. Different categories of weight are defined with the following cutoffs as defined by the World Health Organization Centers for Disease Control and Prevention and the National Institutes of Health:

BMI table

The following chart can help you identify your BMI estimate:

BMI Chart

High BMI (>30) is associated with higher rates of all-causes of mortality, as well as increased rates of type 2 diabetes, cancer, heart disease, and stroke. For additional information see here.

An article published in Nature evaluated and compared the Body-Mass Index (BMI) of populations in rural and urban communities around the world:

NCD Risk Factor Collaboration (NCD-RisC). Rising rural body-mass index is the main driver of the global obesity epidemic in adults. Nature 569, 260–264 (2019).

This article challenged the widely-held view that increased urbanization was one of the major reasons for increased global obesity rates. This view came about because many countries around the world have shown increased urbanization levels in parallel with increased obesity rates. However this study demonstrated that this might not be the case; and that in fact for most regions around the world, BMI measurements are increasing in rural populations just as much if not more so than urban populations. This case study will evaluate the data reported in this article to explore regional and gender specific differences in the obesity rates around the world in 1985 and 2017. Most importantly we will test if there is a difference in obesity rates between rural and urban communities. To do this we will test if there is a difference between the means of the measurements for each group.

Our main questions are:

  1. Is there a difference between rural and urban BMI estimates around the world? How does this compare for males and females?
  2. How have BMI estimates changed from 1985 to 2017?
  3. How do different countries compare for BMI estimates- in particular, how does the United States compare to the rest of the world?

In this case study, we’ll walk you through importing data from a pdf, cleaning data, wrangling data, visualizing the data, and comparing the means of two groups using well-established and commonly used packages, including stringr, tidyr, dplyr, purrr, and ggplot2. We will especially focus on using packages and functions from the Tidyverse. The Tidyverse is a library of packages created by the chief scientist at RStudio, Hadley Wickham. While some students may be familiar with previous R programming packages, these packages make data science in R especially efficient.

We will begin by loading the packages that we will need:

Package Use
here to easily load and save data
pdftools to read a pdf into R
stringr to manipulate the text within the pdf of the data
readr to manipulate the text within the pdf of the data into individual lines
dplyr to arrange/filter/select subsets of the data
tibble to create data objects that we can manipulate with dplyr/stringr/tidyr/purrr
magrittr to use the %<>% pipping operator
glue to paste or combine character strings and data together
purrr to perform functions on all columns of a tibble
tidyr to convert data from wide to long format
ggplot2 to make visualizations with multiple layers
ggrepel to allow labels in figures not to overlap
cowplot to allow plots to be combined

The first time we use a function, we will use the :: to indicate which package we are using. Unless we have overlapping function names, this is not necessary, but we will include it here to be informative about where the functions we will use come from.

Context

The measurement of BMI has some limitations that are well recognized, as it does not account for the composition of body mass, the location of body fat, or the contribution of body frame size. However, BMI has been a useful health indicator for risk for many diseases and conditions particularly when combined with other risk factor information.

What are the data?

We will be using data located within a table of the supplementary material for the NCD-RisC paper referenced above. This is a pdf that can be found freely available online.

Here you can see that the data contains mean BMI values for both men and women in various countries at the national level, as well as the mean BMI values for the rural and urban areas of these countries for both 1985 and 2017.

The data within the parentheses are the 95 % credible interval (CIs) ranges for the mean BMI estimates. The authors provide these CIs as a guide to understand how likely the estimate is for the true population mean BMI. A wider range suggests that the estimate is less accurate, as there are more possible values for the true mean with credible evidence.

Note: While gender and sex are not actually binary, the data presented that is used in this analysis only contains data for groups of individuals described as men or women.

Data Import

First let’s download the data:

Now that we have the obesity pdf, we will read it in to R using the pdftools package:

Let’s take a look at the data- the summary() function helps us to look at the structure of R objects.

   Length     Class      Mode 
       63 character character 

We can see that we have 63 elements that are character strings. You may also notice that the original PDF has 63 pages. Let’s take a look at some of these elements.

[1] "Letter                                                                                https://doi.org/10.1038/s41586-019-1171-x\nRising rural body-mass index is the main driver of\nthe global obesity epidemic in adults\nNCD Risk Factor Collaboration (NCD-RisC)*\n*A list of authors and their affiliations appears in the online version of the paper.\n2 6 0 | N A T U RE | V O L 5 6 9 | 9 M A Y 2 0 1 9\n"
[1] "Supplementary Information. Statistical model for estimating BMI trends by rural and urban\nplace of residence.\n                                          1\n"

We can see that the output looks pretty similar to the pages of the pdf, but the spacing is a bit awkward. Note that the way the data is displayed is partially influenced by the width setting of the RStudio window.

We are interested in a supplementary Table 3. which has multiple pages and includes the same header on each page; we can use that to determine what elements of our pdf_obesity character strings include our table. We will use the str_detect() function of the stringr package to search for the elements that contain text that is consistently in the header. The output of of this function will show which elements of the object (in this case pages of the pdf) include this pattern indicated as a “TRUE” or “FALSE”.

 [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[12] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[23] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[34] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[45] FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE
[56]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE FALSE

Now we will extract just the data for the table now and call it rural_urban. To do this we will use the str_subset() function of the stringr package.

 chr [1:10] "                                                                          2                                    "| __truncated__ ...

Let’s check the first and last page:

This looks the same as the beginning… how about the end?

Great! Our rural_urban object looks like it contains the entire Supplementary 3 table, as both the beginning and the end include the data we expected.

Data Wrangling

At this point we have large strings now for each page of the table, but this is not very convenient to work with. Now we will wrangle the data into a more usable form. Ideally we would like our data to be in some sort of tabular form.

Separate the data into lines

First it would be useful to separate the data into lines or rows of the table.

 chr [1:461] "                                                                          2                                    "| __truncated__ ...
[1] "Afghanistan          Women   20.6 (18.4-22.8)      20.1 (17.8-22.4)     23.2 (20.9-25.4) 24.4 (23.3-25.4)      23.6 (22.5-24.8)     26.3 (25.1-27.4)"

Removing excess white-space

We also have a lot of white-space… let’s get rid of the excess white spaces using str_squish() also from the stringr package.

[1] "2 2"                                                                                                                    
[2] "Age-standardised mean BMI in 1985 (kg/m ) Age-standardised mean BMI in 2017 (kg/m )"                                    
[3] "Country Sex"                                                                                                            
[4] "National Rural Urban National Rural Urban"                                                                              
[5] "Men 20.2 (17.8-22.7) 19.7 (17.2-22.2) 22.4 (20.0-25.0) 22.8 (20.3-25.3) 22.5 (20.0-25.0) 23.6 (21.0-26.1)"              
[6] "Afghanistan Women 20.6 (18.4-22.8) 20.1 (17.8-22.4) 23.2 (20.9-25.4) 24.4 (23.3-25.4) 23.6 (22.5-24.8) 26.3 (25.1-27.4)"

Now it is much easier to see the data.

If we look at the end of the first page of the table and the start of the second we can see that the header information is repeated, as well as a line with the page number and an empty line, and a line that says “2 2”.

 [1] "Benin Women 20.6 (19.1-22.0) 20.1 (18.5-21.6) 21.8 (20.3-23.3) 24.3 (23.5-25.0) 23.2 (22.5-24.0) 25.5 (24.7-26.3)"  
 [2] "Men 24.3 (21.8-26.8) na* 24.3 (21.8-26.8) 26.7 (24.3-29.2) na* 26.7 (24.3-29.2)"                                    
 [3] "Bermuda Women 25.4 (22.2-28.6) na* 25.4 (22.2-28.6) 28.5 (25.3-31.6) na* 28.5 (25.3-31.6)"                          
 [4] "Men 20.6 (19.1-22.1) 20.3 (18.7-21.8) 23.1 (21.5-24.6) 23.5 (22.8-24.3) 23.1 (22.2-23.9) 24.2 (23.3-25.2)"          
 [5] "Bhutan Women 20.7 (18.4-22.9) 20.3 (18.0-22.6) 23.0 (20.8-25.3) 24.6 (23.7-25.5) 23.8 (22.7-24.9) 25.9 (24.7-27.0)" 
 [6] "51"                                                                                                                 
 [7] ""                                                                                                                   
 [8] "2 2"                                                                                                                
 [9] "Age-standardised mean BMI in 1985 (kg/m ) Age-standardised mean BMI in 2017 (kg/m )"                                
[10] "Country Sex"                                                                                                        
[11] "National Rural Urban National Rural Urban"                                                                          
[12] "Men 23.3 (21.0-25.5) 22.9 (20.6-25.2) 23.6 (21.3-25.9) 26.1 (23.9-28.4) 25.3 (23.1-27.5) 26.5 (24.2-28.8)"          
[13] "Bolivia Women 23.8 (22.3-25.3) 23.0 (21.4-24.5) 24.6 (23.1-26.1) 27.9 (26.5-29.3) 27.0 (25.6-28.5) 28.3 (26.8-29.7)"

Although the header was necessary on all of the pages of the pdf version of the table, we only need that information once in our data.

Removing unnecessary repeated header information

So, let’s remove all the header information and the page number lines from the rural_urban object, then we will make a single line header for the beginning. One way to do this is to find all lines that include either “women” or “men” and only keep this data. First let’s see how many lines include “women” or “men”. We can do this by first identifying the lines that contain these patterns and then check the length of the resulting vector for the line numbers that contain these patterns.

  [1]   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21
 [18]  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38
 [35]  39  40  41  42  43  44  45  46  47  48  55  56  57  58  59  60  61
 [52]  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78
 [69]  79  80  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95
 [86]  96  97  98 105 106 107 108 109 110 111 112 113 114 115 116 117 118
[103] 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
[120] 136 137 138 139 140 141 142 143 144 145 146 147 148 155 156 157 158
[137] 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
[154] 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
[171] 193 194 195 196 197 198 205 206 207 208 209 210 211 212 213 214 215
[188] 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
[205] 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 255
[222] 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
[239] 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
[256] 290 291 292 293 294 295 296 297 298 305 306 307 308 309 310 311 312
[273] 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
[290] 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
[307] 347 348 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
[324] 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
[341] 387 388 389 390 391 392 393 394 395 396 397 398 405 406 407 408 409
[358] 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
[375] 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
[392] 444 445 446 447 448 455 456 457 458
[1] 400

OK, so this looks correct. This includes most lines but there are gaps where are header is located. It looks like there are 400 lines in our table that aren’t headers.

We can check our data now using either head() or glimpse().

 chr [1:400] "Men 20.2 (17.8-22.7) 19.7 (17.2-22.2) 22.4 (20.0-25.0) 22.8 (20.3-25.3) 22.5 (20.0-25.0) 23.6 (21.0-26.1)" ...

Great, now our rural_urban object 400 lines instead of 461, like it did before when it contained the redundant header information.

[1] "Men 20.2 (17.8-22.7) 19.7 (17.2-22.2) 22.4 (20.0-25.0) 22.8 (20.3-25.3) 22.5 (20.0-25.0) 23.6 (21.0-26.1)"              
[2] "Afghanistan Women 20.6 (18.4-22.8) 20.1 (17.8-22.4) 23.2 (20.9-25.4) 24.4 (23.3-25.4) 23.6 (22.5-24.8) 26.3 (25.1-27.4)"
[3] "Men 25.2 (23.9-26.5) 25.0 (23.7-26.4) 25.4 (24.0-26.7) 27.0 (26.0-27.9) 26.9 (25.9-27.9) 27.0 (26.0-28.0)"              
[4] "Albania Women 26.0 (24.1-27.9) 26.1 (24.1-28.1) 25.9 (23.9-27.8) 26.0 (24.8-27.2) 26.2 (24.8-27.5) 25.9 (24.6-27.2)"    
[5] "Men 22.1 (20.8-23.3) 21.8 (20.5-23.1) 22.3 (21.0-23.6) 25.1 (24.5-25.7) 24.8 (24.1-25.4) 25.2 (24.6-25.9)"              
[6] "Algeria Women 24.0 (22.2-25.7) 23.3 (21.4-25.1) 24.8 (22.9-26.6) 27.4 (26.7-28.0) 27.0 (26.3-27.8) 27.5 (26.7-28.2)"    

The head() function shows us the first rows or lines of the data, while the glimpse() function provides us information about the total size of the object and shows us the first line or row.

Great! So now our data looks much better but we need to add back our header and we would like this to only be a single line to make it easy to transform our data into a table or table-like object.

Here is what our header used to look like:

Dealing with spacing

First let’s try splitting our header-less data into columns based on spaces using the str_split() function, where we specify that we are splitting the data based on the pattern of a space (the space is included in quotes):

      [,1]          [,2]    [,3]          [,4]          [,5]         
 [1,] "Men"         "20.2"  "(17.8-22.7)" "19.7"        "(17.2-22.2)"
 [2,] "Afghanistan" "Women" "20.6"        "(18.4-22.8)" "20.1"       
 [3,] "Men"         "25.2"  "(23.9-26.5)" "25.0"        "(23.7-26.4)"
 [4,] "Albania"     "Women" "26.0"        "(24.1-27.9)" "26.1"       
 [5,] "Men"         "22.1"  "(20.8-23.3)" "21.8"        "(20.5-23.1)"
 [6,] "Algeria"     "Women" "24.0"        "(22.2-25.7)" "23.3"       
 [7,] "Men"         "33.7"  "(32.7-34.7)" "32.6"        "(31.7-33.5)"
 [8,] "American"    "Samoa" "Women"       "34.3"        "(33.1-35.6)"
 [9,] "Men"         "25.0"  "(22.5-27.4)" "25.3"        "(22.8-27.7)"
[10,] "Andorra"     "Women" "25.2"        "(22.0-28.4)" "25.4"       
      [,6]          [,7]          [,8]          [,9]         
 [1,] "22.4"        "(20.0-25.0)" "22.8"        "(20.3-25.3)"
 [2,] "(17.8-22.4)" "23.2"        "(20.9-25.4)" "24.4"       
 [3,] "25.4"        "(24.0-26.7)" "27.0"        "(26.0-27.9)"
 [4,] "(24.1-28.1)" "25.9"        "(23.9-27.8)" "26.0"       
 [5,] "22.3"        "(21.0-23.6)" "25.1"        "(24.5-25.7)"
 [6,] "(21.4-25.1)" "24.8"        "(22.9-26.6)" "27.4"       
 [7,] "34.0"        "(32.9-35.1)" "34.3"        "(33.0-35.6)"
 [8,] "34.1"        "(33.0-35.2)" "34.4"        "(33.0-35.8)"
 [9,] "25.0"        "(22.5-27.4)" "26.8"        "(24.4-29.2)"
[10,] "(22.2-28.7)" "25.2"        "(22.0-28.4)" "25.3"       
      [,10]         [,11]         [,12]         [,13]        
 [1,] "22.5"        "(20.0-25.0)" "23.6"        "(21.0-26.1)"
 [2,] "(23.3-25.4)" "23.6"        "(22.5-24.8)" "26.3"       
 [3,] "26.9"        "(25.9-27.9)" "27.0"        "(26.0-28.0)"
 [4,] "(24.8-27.2)" "26.2"        "(24.8-27.5)" "25.9"       
 [5,] "24.8"        "(24.1-25.4)" "25.2"        "(24.6-25.9)"
 [6,] "(26.7-28.0)" "27.0"        "(26.3-27.8)" "27.5"       
 [7,] "34.6"        "(33.1-35.9)" "34.2"        "(32.9-35.6)"
 [8,] "35.3"        "(33.7-36.9)" "35.0"        "(33.1-36.9)"
 [9,] "26.8"        "(24.3-29.2)" "26.8"        "(24.3-29.3)"
[10,] "(22.1-28.6)" "25.2"        "(21.9-28.5)" "25.3"       
      [,14]         [,15]         [,16] [,17] [,18]
 [1,] ""            ""            ""    ""    ""   
 [2,] "(25.1-27.4)" ""            ""    ""    ""   
 [3,] ""            ""            ""    ""    ""   
 [4,] "(24.6-27.2)" ""            ""    ""    ""   
 [5,] ""            ""            ""    ""    ""   
 [6,] "(26.7-28.2)" ""            ""    ""    ""   
 [7,] ""            ""            ""    ""    ""   
 [8,] "35.4"        "(33.7-37.1)" ""    ""    ""   
 [9,] ""            ""            ""    ""    ""   
[10,] "(22.1-28.6)" ""            ""    ""    ""   

This almost worked, but unfortunately country names that have spaces will be a problem. We can see that American Samoa has been divided into two columns and all subsequent columns are shifted.

So now let’s try to extract the country information, by separating the country information from the sex information when the sex is female.

Sex always starts with either a capital “W” if the gender is female. #We need to use a space before the “W” otherwise we will split some of the country names if the names starts with “W”.

Here we will also introduce the concept of piping, which uses the %>%. This is really useful when we have multiple steps, which we will show soon.

So first we will select just the data for Women and then split this data based on the pattern " Women" (Note that the space is included - so that it is not within the country data).

[1] "Afghanistan"                                                                                           
[2] " 20.6 (18.4-22.8) 20.1 (17.8-22.4) 23.2 (20.9-25.4) 24.4 (23.3-25.4) 23.6 (22.5-24.8) 26.3 (25.1-27.4)"
[3] "Albania"                                                                                               
[4] " 26.0 (24.1-27.9) 26.1 (24.1-28.1) 25.9 (23.9-27.8) 26.0 (24.8-27.2) 26.2 (24.8-27.5) 25.9 (24.6-27.2)"
[5] "Algeria"                                                                                               
[6] " 24.0 (22.2-25.7) 23.3 (21.4-25.1) 24.8 (22.9-26.6) 27.4 (26.7-28.0) 27.0 (26.3-27.8) 27.5 (26.7-28.2)"

Now we can see that Country is always the odd rows and the rest of the data is the rest of the rows. We can select the odd rows using the Modulus (Remainder from division) operator. This operator looks like this %%. All odd values such as 3, 7, or 15 when divided by 2 would leave a remainder of 1. We will select just these rows using the filter() function of dplyr.

We can take a look to make sure that all the country names look as expected:

# A tibble: 200 x 1
   country_split      
   <chr>              
 1 Afghanistan        
 2 Albania            
 3 Algeria            
 4 American Samoa     
 5 Andorra            
 6 Angola             
 7 Antigua and Barbuda
 8 Argentina          
 9 Armenia            
10 Australia          
# … with 190 more rows

Looks good!

The even rows are the rows with the data for women. These row values have a remainder of 0 when divided by 2.

# A tibble: 6 x 1
  country_split                                                            
  <chr>                                                                    
1 " 20.6 (18.4-22.8) 20.1 (17.8-22.4) 23.2 (20.9-25.4) 24.4 (23.3-25.4) 23…
2 " 26.0 (24.1-27.9) 26.1 (24.1-28.1) 25.9 (23.9-27.8) 26.0 (24.8-27.2) 26…
3 " 24.0 (22.2-25.7) 23.3 (21.4-25.1) 24.8 (22.9-26.6) 27.4 (26.7-28.0) 27…
4 " 34.3 (33.1-35.6) 34.1 (33.0-35.2) 34.4 (33.0-35.8) 35.3 (33.7-36.9) 35…
5 " 25.2 (22.0-28.4) 25.4 (22.2-28.7) 25.2 (22.0-28.4) 25.3 (22.1-28.6) 25…
6 " 21.3 (18.0-24.6) 20.9 (17.6-24.3) 22.7 (19.3-26.0) 24.4 (21.2-27.7) 23…

Great! Now we have a list of the countries that can be used for both the male and female data.

It’s always a good idea to check that your data objects are the size you expect when wrangling. We can do so with the dim() function, which shows us the dimensions of data objects.

[1] 200   1

Great! There are 200 rows like we expected.

We do however need to add " Women" back to this data.

To do this we will use the glue() function of the glue package.

Women 20.6 (18.4-22.8) 20.1 (17.8-22.4) 23.2 (20.9-25.4) 24.4 (23.3-25.4) 23.6 (22.5-24.8) 26.3 (25.1-27.4)
Women 26.0 (24.1-27.9) 26.1 (24.1-28.1) 25.9 (23.9-27.8) 26.0 (24.8-27.2) 26.2 (24.8-27.5) 25.9 (24.6-27.2)
Women 24.0 (22.2-25.7) 23.3 (21.4-25.1) 24.8 (22.9-26.6) 27.4 (26.7-28.0) 27.0 (26.3-27.8) 27.5 (26.7-28.2)
Women 34.3 (33.1-35.6) 34.1 (33.0-35.2) 34.4 (33.0-35.8) 35.3 (33.7-36.9) 35.0 (33.1-36.9) 35.4 (33.7-37.1)
Women 25.2 (22.0-28.4) 25.4 (22.2-28.7) 25.2 (22.0-28.4) 25.3 (22.1-28.6) 25.2 (21.9-28.5) 25.3 (22.1-28.6)
Women 21.3 (18.0-24.6) 20.9 (17.6-24.3) 22.7 (19.3-26.0) 24.4 (21.2-27.7) 23.3 (20.0-26.7) 25.7 (22.4-29.1)

Let’s grab the male data:

[1] "Men 20.2 (17.8-22.7) 19.7 (17.2-22.2) 22.4 (20.0-25.0) 22.8 (20.3-25.3) 22.5 (20.0-25.0) 23.6 (21.0-26.1)"
[2] "Men 25.2 (23.9-26.5) 25.0 (23.7-26.4) 25.4 (24.0-26.7) 27.0 (26.0-27.9) 26.9 (25.9-27.9) 27.0 (26.0-28.0)"
[3] "Men 22.1 (20.8-23.3) 21.8 (20.5-23.1) 22.3 (21.0-23.6) 25.1 (24.5-25.7) 24.8 (24.1-25.4) 25.2 (24.6-25.9)"
[4] "Men 33.7 (32.7-34.7) 32.6 (31.7-33.5) 34.0 (32.9-35.1) 34.3 (33.0-35.6) 34.6 (33.1-35.9) 34.2 (32.9-35.6)"
[5] "Men 25.0 (22.5-27.4) 25.3 (22.8-27.7) 25.0 (22.5-27.4) 26.8 (24.4-29.2) 26.8 (24.3-29.2) 26.8 (24.3-29.3)"
[6] "Men 20.5 (17.9-23.1) 20.2 (17.6-22.9) 21.4 (18.8-24.0) 22.6 (20.0-25.1) 22.0 (19.4-24.6) 23.2 (20.6-25.9)"
[1] 200   1

How about our number of columns?

If we try splitting our data by space again, will it have the expected number of columns? What about the rows that contain na* values?

# A tibble: 5 x 12
  V1    V2    V3     V4    V5     V6    V7    V8    V9    V10   V11   V12  
  <chr> <chr> <chr>  <chr> <chr>  <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 Men   24.3  (21.8… na*   24.3   (21.… 26.7  (24.… na*   26.7  (24.… ""   
2 Men   22.4  (21.4… 21.5  (20.2… 22.4  (21.… 24.8  (23.… na*   24.8  (23.…
3 Men   32.6  (32.0… na*   32.6   (32.… 32.9  (31.… na*   32.9  (31.… ""   
4 Men   22.8  (22.2… na*   22.8   (22.… 24.4  (23.… na*   24.4  (23.… ""   
5 Men   29.6  (28.1… 29.6  (28.1… na*   32.3  (31.… 32.3  (31.… na*   ""   

Dealing with NA values

So close! Notice that the "na*" values have shifted the subsequent values within the columns because typically there is a space between the BMI and the credible intervals. Here we can see this data in our original pdf:

We need to replace our na* values with something that includes a space so that when we separate our data by space we will have two values instead of one when we have an na* . Therefore, na* na* should work.

[1] "character"

Let’s check that it worked…

 [1] "Men 20.7 (19.4-22.1) 20.3 (18.9-21.7) 21.7 (20.3-23.1) 22.7 (22.0-23.3) 22.1 (21.3-22.8) 23.4 (22.7-24.1)"
 [2] "Men 24.3 (21.8-26.8) na* na* 24.3 (21.8-26.8) 26.7 (24.3-29.2) na* na* 26.7 (24.3-29.2)"                  
 [3] "Men 20.6 (19.1-22.1) 20.3 (18.7-21.8) 23.1 (21.5-24.6) 23.5 (22.8-24.3) 23.1 (22.2-23.9) 24.2 (23.3-25.2)"
 [4] "Men 23.3 (21.0-25.5) 22.9 (20.6-25.2) 23.6 (21.3-25.9) 26.1 (23.9-28.4) 25.3 (23.1-27.5) 26.5 (24.2-28.8)"
 [5] "Men 24.9 (23.5-26.2) 24.8 (23.4-26.2) 25.0 (23.6-26.4) 26.8 (25.7-27.8) 26.7 (25.7-27.8) 26.8 (25.7-27.9)"
 [6] "Men 20.6 (19.2-22.0) 20.3 (18.8-21.7) 21.4 (20.0-22.9) 22.6 (21.9-23.4) 21.9 (20.9-22.8) 23.2 (22.3-24.0)"
 [7] "Men 23.3 (22.5-24.0) 22.2 (21.4-23.0) 23.7 (22.9-24.5) 26.2 (25.7-26.7) 25.0 (24.3-25.6) 26.4 (25.9-26.9)"
 [8] "Men 24.0 (22.5-25.4) 23.7 (22.1-25.1) 24.2 (22.7-25.7) 27.1 (26.4-27.7) 26.6 (26.0-27.3) 27.2 (26.5-27.9)"
 [9] "Men 25.0 (23.8-26.4) 24.9 (23.5-26.4) 25.1 (23.8-26.5) 27.0 (25.8-28.1) 27.0 (25.7-28.3) 27.0 (25.7-28.2)"
[10] "Men 20.2 (18.8-21.5) 20.0 (18.6-21.4) 21.4 (19.9-22.9) 22.2 (21.4-23.0) 21.8 (21.0-22.6) 23.1 (22.1-24.1)"
[11] "Men 20.2 (17.7-22.6) 20.1 (17.6-22.5) 21.2 (18.7-23.6) 22.1 (19.8-24.5) 22.0 (19.6-24.3) 23.2 (20.8-25.6)"

Great!

Now for the Women data object

[1] "glue"      "character"
 [1] "Women 20.6 (19.1-22.0) 20.1 (18.5-21.6) 21.8 (20.3-23.3) 24.3 (23.5-25.0) 23.2 (22.5-24.0) 25.5 (24.7-26.3)"
 [2] "Women 25.4 (22.2-28.6) na* na* 25.4 (22.2-28.6) 28.5 (25.3-31.6) na* na* 28.5 (25.3-31.6)"                  
 [3] "Women 20.7 (18.4-22.9) 20.3 (18.0-22.6) 23.0 (20.8-25.3) 24.6 (23.7-25.5) 23.8 (22.7-24.9) 25.9 (24.7-27.0)"
 [4] "Women 23.8 (22.3-25.3) 23.0 (21.4-24.5) 24.6 (23.1-26.1) 27.9 (26.5-29.3) 27.0 (25.6-28.5) 28.3 (26.8-29.7)"
 [5] "Women 25.5 (23.5-27.4) 25.7 (23.7-27.7) 25.1 (23.1-27.0) 25.7 (24.4-27.1) 26.0 (24.6-27.5) 25.3 (23.9-26.8)"
 [6] "Women 24.2 (22.2-26.2) 23.7 (21.5-25.8) 25.6 (23.5-27.7) 26.2 (25.3-27.1) 25.0 (23.8-26.2) 27.0 (26.0-28.2)"
 [7] "Women 24.0 (23.2-25.0) 23.1 (22.1-24.1) 24.4 (23.5-25.4) 26.9 (26.2-27.5) 26.4 (25.7-27.2) 26.9 (26.3-27.6)"
 [8] "Women 23.6 (21.4-25.6) 22.9 (20.7-25.0) 24.0 (21.8-26.1) 27.4 (26.6-28.1) 27.0 (26.1-27.8) 27.5 (26.7-28.2)"
 [9] "Women 25.2 (23.4-27.1) 25.5 (23.4-27.6) 25.0 (23.1-26.9) 25.6 (24.1-27.1) 26.0 (24.2-27.8) 25.5 (23.9-27.1)"
[10] "Women 19.9 (18.7-21.2) 19.6 (18.4-20.9) 22.0 (20.7-23.3) 22.2 (21.4-23.1) 21.1 (20.2-22.0) 24.7 (23.7-25.7)"
[11] "Women 19.6 (17.5-21.7) 19.5 (17.4-21.6) 21.7 (19.5-23.8) 21.1 (20.3-22.0) 20.7 (19.8-21.6) 24.0 (23.0-24.9)"

Great, now we can split our data by spaces.

Splitting the data

# A tibble: 6 x 13
  V1    V2    V3     V4    V5     V6    V7    V8    V9    V10   V11   V12  
  <chr> <chr> <chr>  <chr> <chr>  <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 Men   20.2  (17.8… 19.7  (17.2… 22.4  (20.… 22.8  (20.… 22.5  (20.… 23.6 
2 Men   25.2  (23.9… 25.0  (23.7… 25.4  (24.… 27.0  (26.… 26.9  (25.… 27.0 
3 Men   22.1  (20.8… 21.8  (20.5… 22.3  (21.… 25.1  (24.… 24.8  (24.… 25.2 
4 Men   33.7  (32.7… 32.6  (31.7… 34.0  (32.… 34.3  (33.… 34.6  (33.… 34.2 
5 Men   25.0  (22.5… 25.3  (22.8… 25.0  (22.… 26.8  (24.… 26.8  (24.… 26.8 
6 Men   20.5  (17.9… 20.2  (17.6… 21.4  (18.… 22.6  (20.… 22.0  (19.… 23.2 
# … with 1 more variable: V13 <chr>
# A tibble: 6 x 13
  V1    V2    V3     V4    V5     V6    V7    V8    V9    V10   V11   V12  
  <chr> <chr> <chr>  <chr> <chr>  <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 Women 20.6  (18.4… 20.1  (17.8… 23.2  (20.… 24.4  (23.… 23.6  (22.… 26.3 
2 Women 26.0  (24.1… 26.1  (24.1… 25.9  (23.… 26.0  (24.… 26.2  (24.… 25.9 
3 Women 24.0  (22.2… 23.3  (21.4… 24.8  (22.… 27.4  (26.… 27.0  (26.… 27.5 
4 Women 34.3  (33.1… 34.1  (33.0… 34.4  (33.… 35.3  (33.… 35.0  (33.… 35.4 
5 Women 25.2  (22.0… 25.4  (22.2… 25.2  (22.… 25.3  (22.… 25.2  (21.… 25.3 
6 Women 21.3  (18.0… 20.9  (17.6… 22.7  (19.… 24.4  (21.… 23.3  (20.… 25.7 
# … with 1 more variable: V13 <chr>
# A tibble: 11 x 13
   V1    V2    V3     V4    V5    V6    V7    V8    V9    V10   V11   V12  
   <chr> <chr> <chr>  <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
 1 Women 20.6  (19.1… 20.1  (18.… 21.8  (20.… 24.3  (23.… 23.2  (22.… 25.5 
 2 Women 25.4  (22.2… na*   na*   25.4  (22.… 28.5  (25.… na*   na*   28.5 
 3 Women 20.7  (18.4… 20.3  (18.… 23.0  (20.… 24.6  (23.… 23.8  (22.… 25.9 
 4 Women 23.8  (22.3… 23.0  (21.… 24.6  (23.… 27.9  (26.… 27.0  (25.… 28.3 
 5 Women 25.5  (23.5… 25.7  (23.… 25.1  (23.… 25.7  (24.… 26.0  (24.… 25.3 
 6 Women 24.2  (22.2… 23.7  (21.… 25.6  (23.… 26.2  (25.… 25.0  (23.… 27.0 
 7 Women 24.0  (23.2… 23.1  (22.… 24.4  (23.… 26.9  (26.… 26.4  (25.… 26.9 
 8 Women 23.6  (21.4… 22.9  (20.… 24.0  (21.… 27.4  (26.… 27.0  (26.… 27.5 
 9 Women 25.2  (23.4… 25.5  (23.… 25.0  (23.… 25.6  (24.… 26.0  (24.… 25.5 
10 Women 19.9  (18.7… 19.6  (18.… 22.0  (20.… 22.2  (21.… 21.1  (20.… 24.7 
11 Women 19.6  (17.5… 19.5  (17.… 21.7  (19.… 21.1  (20.… 20.7  (19.… 24.0 
# … with 1 more variable: V13 <chr>

Looks good!

Adding new header

We can see from our pdf and our object called header what the header was like. Let’s also make a new single line header, but let’s wait to add Country:

Let’s change the names of our columns of our tibbles to this new header for our Men and Women data

Now we will add our country data to both our Men and Women tibbles using the bind_cols() function:

# A tibble: 6 x 14
  country_split Sex   National_BMI_19… National_BMI_19… Rural_BMI_1985
  <chr>         <chr> <chr>            <chr>            <chr>         
1 Afghanistan   Women 20.6             (18.4-22.8)      20.1          
2 Albania       Women 26.0             (24.1-27.9)      26.1          
3 Algeria       Women 24.0             (22.2-25.7)      23.3          
4 American Sam… Women 34.3             (33.1-35.6)      34.1          
5 Andorra       Women 25.2             (22.0-28.4)      25.4          
6 Angola        Women 21.3             (18.0-24.6)      20.9          
# … with 9 more variables: Rural_BMI_1985_CI <chr>, Urban_BMI_1985 <chr>,
#   Urban_BMI_1985_CI <chr>, National_BMI_2017 <chr>,
#   National_BMI_2017_CI <chr>, Rural_BMI_2017 <chr>,
#   Rural_BMI_2017_CI <chr>, Urban_BMI_2017 <chr>, Urban_BMI_2017_CI <chr>

Changing variable names

Here we will change the variable name of the country data to country, currently it is called country_split. Here we will also introduce the concept of the assignment pipe. In this case our pipe operator looks like this %<>% . Using this fancier pipe requires another package, called magrittr. The other simpler pipe options from this package are loaded with tidyverse (if you used library(tidyverse) which loads most tidyverse packages), but not this fancier version.

The > portion of the pipe still behaves like a normal pipe, while the < portion of the pipe makes an assignment to whatever the <is pointing to, just like when we use the typical assignment operator <-.

Joining the data

Now we can combine our Men and Women data using the full_join() function of dplyr. This will put all the male data first (x) and all the female data second (y).

Classes 'tbl_df', 'tbl' and 'data.frame':   400 obs. of  14 variables:
 $ Country             : chr  "Afghanistan" "Albania" "Algeria" "American Samoa" ...
 $ Sex                 : chr  "Men" "Men" "Men" "Men" ...
 $ National_BMI_1985   : chr  "20.2" "25.2" "22.1" "33.7" ...
 $ National_BMI_1985_CI: chr  "(17.8-22.7)" "(23.9-26.5)" "(20.8-23.3)" "(32.7-34.7)" ...
 $ Rural_BMI_1985      : chr  "19.7" "25.0" "21.8" "32.6" ...
 $ Rural_BMI_1985_CI   : chr  "(17.2-22.2)" "(23.7-26.4)" "(20.5-23.1)" "(31.7-33.5)" ...
 $ Urban_BMI_1985      : chr  "22.4" "25.4" "22.3" "34.0" ...
 $ Urban_BMI_1985_CI   : chr  "(20.0-25.0)" "(24.0-26.7)" "(21.0-23.6)" "(32.9-35.1)" ...
 $ National_BMI_2017   : chr  "22.8" "27.0" "25.1" "34.3" ...
 $ National_BMI_2017_CI: chr  "(20.3-25.3)" "(26.0-27.9)" "(24.5-25.7)" "(33.0-35.6)" ...
 $ Rural_BMI_2017      : chr  "22.5" "26.9" "24.8" "34.6" ...
 $ Rural_BMI_2017_CI   : chr  "(20.0-25.0)" "(25.9-27.9)" "(24.1-25.4)" "(33.1-35.9)" ...
 $ Urban_BMI_2017      : chr  "23.6" "27.0" "25.2" "34.2" ...
 $ Urban_BMI_2017_CI   : chr  "(21.0-26.1)" "(26.0-28.0)" "(24.6-25.9)" "(32.9-35.6)" ...

Sorting the data

Now Lets sort the data by country:

# A tibble: 6 x 14
  Country Sex   National_BMI_19… National_BMI_19… Rural_BMI_1985
  <chr>   <chr> <chr>            <chr>            <chr>         
1 Afghan… Men   20.2             (17.8-22.7)      19.7          
2 Afghan… Women 20.6             (18.4-22.8)      20.1          
3 Albania Men   25.2             (23.9-26.5)      25.0          
4 Albania Women 26.0             (24.1-27.9)      26.1          
5 Algeria Men   22.1             (20.8-23.3)      21.8          
6 Algeria Women 24.0             (22.2-25.7)      23.3          
# … with 9 more variables: Rural_BMI_1985_CI <chr>, Urban_BMI_1985 <chr>,
#   Urban_BMI_1985_CI <chr>, National_BMI_2017 <chr>,
#   National_BMI_2017_CI <chr>, Rural_BMI_2017 <chr>,
#   Rural_BMI_2017_CI <chr>, Urban_BMI_2017 <chr>, Urban_BMI_2017_CI <chr>

Our data is looking great! Now we might want to make sure that our observations for each variable look the way we want. In other words, if we want to make plots about National BMI in 1985 then we would need our values to be numeric. Looking at our BMI data using str(), we can see the type of data for each of our variables listed just after variable name and the “:” colon. Looks like none of our BMI data is actually numeric, but of the class character. Let’s change that now.

Classes 'tbl_df', 'tbl' and 'data.frame':   400 obs. of  14 variables:
 $ Country             : chr  "Afghanistan" "Afghanistan" "Albania" "Albania" ...
 $ Sex                 : chr  "Men" "Women" "Men" "Women" ...
 $ National_BMI_1985   : chr  "20.2" "20.6" "25.2" "26.0" ...
 $ National_BMI_1985_CI: chr  "(17.8-22.7)" "(18.4-22.8)" "(23.9-26.5)" "(24.1-27.9)" ...
 $ Rural_BMI_1985      : chr  "19.7" "20.1" "25.0" "26.1" ...
 $ Rural_BMI_1985_CI   : chr  "(17.2-22.2)" "(17.8-22.4)" "(23.7-26.4)" "(24.1-28.1)" ...
 $ Urban_BMI_1985      : chr  "22.4" "23.2" "25.4" "25.9" ...
 $ Urban_BMI_1985_CI   : chr  "(20.0-25.0)" "(20.9-25.4)" "(24.0-26.7)" "(23.9-27.8)" ...
 $ National_BMI_2017   : chr  "22.8" "24.4" "27.0" "26.0" ...
 $ National_BMI_2017_CI: chr  "(20.3-25.3)" "(23.3-25.4)" "(26.0-27.9)" "(24.8-27.2)" ...
 $ Rural_BMI_2017      : chr  "22.5" "23.6" "26.9" "26.2" ...
 $ Rural_BMI_2017_CI   : chr  "(20.0-25.0)" "(22.5-24.8)" "(25.9-27.9)" "(24.8-27.5)" ...
 $ Urban_BMI_2017      : chr  "23.6" "26.3" "27.0" "25.9" ...
 $ Urban_BMI_2017_CI   : chr  "(21.0-26.1)" "(25.1-27.4)" "(26.0-28.0)" "(24.6-27.2)" ...

We could change these values to be numeric with 6 lines of code like this:

Classes 'tbl_df', 'tbl' and 'data.frame':   400 obs. of  14 variables:
 $ Country             : chr  "Afghanistan" "Afghanistan" "Albania" "Albania" ...
 $ Sex                 : chr  "Men" "Women" "Men" "Women" ...
 $ National_BMI_1985   : num  20.2 20.6 25.2 26 22.1 24 33.7 34.3 25 25.2 ...
 $ National_BMI_1985_CI: chr  "(17.8-22.7)" "(18.4-22.8)" "(23.9-26.5)" "(24.1-27.9)" ...
 $ Rural_BMI_1985      : num  19.7 20.1 25 26.1 21.8 23.3 32.6 34.1 25.3 25.4 ...
 $ Rural_BMI_1985_CI   : chr  "(17.2-22.2)" "(17.8-22.4)" "(23.7-26.4)" "(24.1-28.1)" ...
 $ Urban_BMI_1985      : num  22.4 23.2 25.4 25.9 22.3 24.8 34 34.4 25 25.2 ...
 $ Urban_BMI_1985_CI   : chr  "(20.0-25.0)" "(20.9-25.4)" "(24.0-26.7)" "(23.9-27.8)" ...
 $ National_BMI_2017   : num  22.8 24.4 27 26 25.1 27.4 34.3 35.3 26.8 25.3 ...
 $ National_BMI_2017_CI: chr  "(20.3-25.3)" "(23.3-25.4)" "(26.0-27.9)" "(24.8-27.2)" ...
 $ Rural_BMI_2017      : num  22.5 23.6 26.9 26.2 24.8 27 34.6 35 26.8 25.2 ...
 $ Rural_BMI_2017_CI   : chr  "(20.0-25.0)" "(22.5-24.8)" "(25.9-27.9)" "(24.8-27.5)" ...
 $ Urban_BMI_2017      : num  23.6 26.3 27 25.9 25.2 27.5 34.2 35.4 26.8 25.3 ...
 $ Urban_BMI_2017_CI   : chr  "(21.0-26.1)" "(25.1-27.4)" "(26.0-28.0)" "(24.6-27.2)" ...

Or we can use a more automated way with the map() function of the purrr package:

# A tibble: 6 x 8
  National_BMI_19… Rural_BMI_1985 Urban_BMI_1985 National_BMI_20…
             <dbl>          <dbl>          <dbl>            <dbl>
1             20.2           19.7           22.4             22.8
2             20.6           20.1           23.2             24.4
3             25.2           25             25.4             27  
4             26             26.1           25.9             26  
5             22.1           21.8           22.3             25.1
6             24             23.3           24.8             27.4
# … with 4 more variables: Rural_BMI_2017 <dbl>, Urban_BMI_2017 <dbl>,
#   Country <chr>, Sex <chr>

It is generally useful to get the data in what is called long format for other analyses, and particularly for plotting.

For a more detailed description about this, please see this case study

Basically what the long format will have more rows and fewer columns. Thus we can combine or “gather” some columns together. In our case we can put all the different BMI data together in one long column. We will create a new column that tells us what each row of the new BMI column represents. In other words, it will tell us what the original column was.

To do this we will use the gather() function of the tidyr package:

# A tibble: 6 x 4
  Country     Sex   class_BMI           BMI
  <chr>       <chr> <chr>             <dbl>
1 Afghanistan Men   National_BMI_1985  20.2
2 Afghanistan Women National_BMI_1985  20.6
3 Albania     Men   National_BMI_1985  25.2
4 Albania     Women National_BMI_1985  26  
5 Algeria     Men   National_BMI_1985  22.1
6 Algeria     Women National_BMI_1985  24  

It would be useful to parse the 1985 and the 2017 data. We can do so by separating the parts of the class_BMI column using the separate() function of the tidyr package. In our case we will replace the class_BMI column with two new columns.

# A tibble: 6 x 5
  Country     Sex   Region   Year    BMI
  <chr>       <chr> <chr>    <chr> <dbl>
1 Afghanistan Men   National 1985   20.2
2 Afghanistan Women National 1985   20.6
3 Albania     Men   National 1985   25.2
4 Albania     Women National 1985   26  
5 Algeria     Men   National 1985   22.1
6 Algeria     Women National 1985   24  
[1] 400   8
[1] 2400    5

Question opportunity: Why exactly are there 2,400 rows now?

Great! our data is very usable now in this format!

Data Exploration

Now that our data is clean and in a format that we can work with, we can start to take a look at the data and how different groups might compare.

Statistically speaking there are tests that can allow us to evaluate if the means of the groups are different. First let’s see how our data looks in general.

General summary

Start here if not working through data import and wrangling

 National_BMI_1985 Rural_BMI_1985 Urban_BMI_1985  National_BMI_2017
 Min.   :18.20     Min.   :17.7   Min.   :19.30   Min.   :20.20    
 1st Qu.:21.50     1st Qu.:20.9   1st Qu.:22.43   1st Qu.:24.07    
 Median :24.00     Median :23.4   Median :24.30   Median :26.15    
 Mean   :23.68     Mean   :23.3   Mean   :24.24   Mean   :26.00    
 3rd Qu.:25.23     3rd Qu.:25.1   3rd Qu.:25.40   3rd Qu.:27.43    
 Max.   :34.30     Max.   :34.1   Max.   :34.40   Max.   :35.30    
                   NA's   :6      NA's   :2                        
 Rural_BMI_2017  Urban_BMI_2017    Country              Sex           
 Min.   :19.80   Min.   :21.50   Length:400         Length:400        
 1st Qu.:23.30   1st Qu.:24.80   Class :character   Class :character  
 Median :26.00   Median :26.30   Mode  :character   Mode  :character  
 Mean   :25.61   Mean   :26.37                                        
 3rd Qu.:27.30   3rd Qu.:27.60                                        
 Max.   :35.00   Max.   :35.40                                        
 NA's   :8       NA's   :2                                            

OK, so our means are fairly similar, but we can see some differences. The question is if those differences are meaningful. This is difficult to determine without a statistical test.

Lets look at the data separately by gender:

 National_BMI_1985 Rural_BMI_1985  Urban_BMI_1985  National_BMI_2017
 Min.   :18.20     Min.   :17.70   Min.   :19.70   Min.   :21.00    
 1st Qu.:22.00     1st Qu.:21.20   1st Qu.:22.85   1st Qu.:24.40    
 Median :24.25     Median :23.90   Median :24.60   Median :26.10    
 Mean   :24.00     Mean   :23.59   Mean   :24.63   Mean   :26.38    
 3rd Qu.:25.50     3rd Qu.:25.40   3rd Qu.:25.60   3rd Qu.:28.00    
 Max.   :34.30     Max.   :34.10   Max.   :34.40   Max.   :35.30    
                   NA's   :3       NA's   :1                        
 Rural_BMI_2017  Urban_BMI_2017    Country              Sex           
 Min.   :20.40   Min.   :21.60   Length:200         Length:200        
 1st Qu.:23.70   1st Qu.:25.30   Class :character   Class :character  
 Median :26.20   Median :26.40   Mode  :character   Mode  :character  
 Mean   :25.98   Mean   :26.84                                        
 3rd Qu.:27.60   3rd Qu.:28.25                                        
 Max.   :35.00   Max.   :35.40                                        
 NA's   :4       NA's   :1                                            
 National_BMI_1985 Rural_BMI_1985  Urban_BMI_1985  National_BMI_2017
 Min.   :18.50     Min.   :18.40   Min.   :19.30   Min.   :20.20    
 1st Qu.:21.10     1st Qu.:20.80   1st Qu.:22.10   1st Qu.:23.30    
 Median :23.60     Median :23.20   Median :24.10   Median :26.20    
 Mean   :23.36     Mean   :23.01   Mean   :23.84   Mean   :25.61    
 3rd Qu.:25.00     3rd Qu.:24.90   3rd Qu.:25.10   3rd Qu.:27.10    
 Max.   :33.70     Max.   :32.60   Max.   :34.00   Max.   :34.30    
                   NA's   :3       NA's   :1                        
 Rural_BMI_2017  Urban_BMI_2017   Country              Sex           
 Min.   :19.80   Min.   :21.5   Length:200         Length:200        
 1st Qu.:22.60   1st Qu.:23.8   Class :character   Class :character  
 Median :25.75   Median :26.3   Mode  :character   Mode  :character  
 Mean   :25.24   Mean   :25.9                                        
 3rd Qu.:27.00   3rd Qu.:27.2                                        
 Max.   :34.60   Max.   :34.2                                        
 NA's   :4       NA's   :1                                           

It looks like mean BMIs have increased in all regions for both men and women. It is unclear though if this change is statistically significant.

Distributions

In order to apply a statistical test to compare the means, one of the first things to do is to plot the frequency of the different possible values. This is called a distribution. To do this we can use the hist() function to create a histogram.

If the data were what we call normally distributed or followed a Gaussian distribution then the distribution should be equally centered around the mean and would look something like this:

# A tibble: 6 x 1
  norm_data
      <dbl>
1      24.6
2      23.1
3      22.6
4      23.7
5      24.4
6      22.7

Alternatively we can plot this using the geom_hist() function of the ggplot2 package. The ggplot2 package creates plots by using layers. Notice in the following code how there is a plus sign between the ggplot() function and the geom_histogram() function. With ggplot2 we select what data we would like to plot using the first function (ggplot()) and then we add on additional layers of complexity (these layers can even involve different data). In this case the geom_histrogram() function initiates the plotting of a histogram with the data that was identified in the ggplot() function. We will see later how we can add many layers to plots with ggplot2. For additional information on using ggplot2, see this case study.

Let’s see how our data looks:

OK, so the data looks like it is what we call right-skewed because the tail of the distribution is longer on the right side (in other words, it is a bit wider on that side), but it looks fairly normally distributed.

If we parse our data, what does it look like? The easiest way to do this is to use some other functions of the ggplot2 package, particularly the facet_wrap() function, which will allow us to look at differences in the distribution of the BMI data by year, gender, and region. We can sequentially divide our plots by deeper levels using multiple variables and the + plus sign within facet_wrap().

OK, so some of these plots look pretty similar to our normal distribution plot, like the Women 2017 Urban plot (although it is right-skewed). However some of the other plots, like the Men 2017 Urban plot, look very different.

Quantile-Quantile Plots

Let’s use a method called the quantile-quantile plot to determine if the data is indeed normally distributed. These plots are called Q-Q plots. This method allows us to test the fit of known theoretical distributions (like the normal distribution) with our observed distribution. To do this we will plot the quantiles of our data on the y-axis and the quantiles of the theoretical normal distribution on the x-axis. If the quantiles line up then we can say that our data is fairly normal. What exactly is a quantile? This is a division of the data distribution into roughly equal portions.

Here is an example of a Q-Q plot for the normally distributed data that we just created using the stat_qq() function of the ggplot2 package:

Here we can see that the quantiles are fairly similar between the observed and theoretical data. We see that the points mostly fall on the line, however there are some points that are a bit further from the line as we get to the extreme quantiles. Notice that the sample quantiles (which will be fairly similar to our real BMI data quantiles) on the y-axis has the same range as the values that we created. So values that are bellow 22 for example are represented as the points bellow 22 on the y-axis. As expected we see that about half the points are bellow our mean of 24.

If we were to use different data that had a range of different values our y-axis would shift according to the range of values. For example the Orange data within the installation of R includes data about the circumference of orange trees in millimeters. Here we can see that the quantiles are quite different but reflect the range of orange tree circumferences.

[1]  30 214

Let’s take a look at our BMI data:

This is a little hard to see, some plots look pretty good, but while others seem to be skewed, lets take a closer look.

For the sake of simplicity, we are going to focus on the data from the women. This is because women were identified in the paper to have larger increases in BMI. If we want to perform tests on these groups specifically, then we need to know how this data looks.

What about by region and year? If we compare these data then we need to look at the distribution of each of these subsets.

We can see that at the extremes of our quantiles, for most of our data, our tails are not very similar to the theoretical distribution. The rural data looks more normal than the urban data, but if we were to use statistical tests that rely on normality, this would require that both groups are normally distributed.

Finally, some statisticians also use the Shapiro-Wilk test for normality when the Q-Q plot is a bit unclear. Many statisticians however would conclude from the Q-Q plots that normality appears to be violated in our data.

Shapiro-Wilk test

For illustrative purposes we will show how we can use the dplyr summarize() and group_by() functions to perform the Shapiro-Wilk test for all the subsets we are interested in.


    Shapiro-Wilk normality test

data:  .
W = 0.99324, p-value = 0.4928
# A tibble: 6 x 3
# Groups:   Year [2]
  Year  Region   shapiro_test
  <chr> <chr>           <dbl>
1 1985  National  0.0000478  
2 1985  Rural     0.000679   
3 1985  Urban     0.000000332
4 2017  National  0.00363    
5 2017  Rural     0.0108     
6 2017  Urban     0.0000130  

We see that all the data does not appear to be normally distributed.

Data Analysis

We can use statistical tests like the student t-test to determine if two means are significantly different.

With the t-test, we perform what is called two means hypothesis tests . We define what is called the null hypothesis , which is what we assume by default or the baseline, that there is no difference in the two means:

                                    Ho: μ1 = μ2
                                    
                           μ1 is the mean of one group
                           μ2 is the mean of the other group
                           

Thus like in law, we accept this null hypothesis, unless we have enough evidence to suggest that we should reject it - similar to the idea that we by default assume that indivudals are not guilty, untill proven otherwise. If we reject the null hypothesis, we then accept an alternative hypothesis , this can vary for different statistical tests, but in the case of the t-test we evaluate if the two means are not equal:

                                    Ha: μ1 ≠ μ2

We are interested in comparing the means of female rural and urban BMI measurements for both years.

There are two possible classes of statistical tests that we could run to compare the means of these two groups:

  1. Parametric
  2. nonparametric

Parametric two sample mean tests

Often when comparing two groups we might perform a two sample t-test to determine if the means of each group is different. The two sample t-test however, relies on several assumptions:

  1. The data for both groups is normally distributed
  2. The variance of both groups is similar
  3. The number of observations is similar for both groups - thus they are balanced

If these assumptions are violated, this doesn’t necessarily mean we can’t perform a t-test. It just means we may have to transform the data to make it normally distributed and we may need to perform the t-test in a special way to account for the difference in the variance in the two groups. Alternatively, we can use a nonparametric test like the Wilcoxon–Mann–Whitney (WMW) test. We will explore these options.

Our data has a balance of observations for both groups - in fact they are equal, thus that assumption is not violated. If it were violated, we would want to consider using permutation methods. To learn more about these methods see here.

If we needed to check if our samples were imbalanced, we could use the table() function:

, ,  = 1985

       
        National Rural Urban
  Men        200   200   200
  Women      200   200   200

, ,  = 2017

       
        National Rural Urban
  Men        200   200   200
  Women      200   200   200

We can see that the number of observations for each possible group of interest is the same.

The t-test is also fairly robust to non-normality if the data is relatively large, and we have an n of 200, which should be sufficient but let’s investigate the nonparametric tests further.

Often we would check if the variance of the rural and urban data is equal using the var.test() function. However this is an F test and assumes that the data is normally distributed. Instead we will use the mood.test() function which performs the Mood’s two-sample test for a difference in scale parameters and does not assume that the data is normally distributed. We will also introduce the pull() function of the dplyr package.


    Mood two-sample test of scale

data:  dplyr::pull(filter(BMI_long, Sex == "Women", Year == "2017",  and dplyr::pull(filter(BMI_long, Sex == "Women", Year == "2017",     Region == "Rural"), BMI) and     Region == "Urban"), BMI)
Z = 2.9189, p-value = 0.003513
alternative hypothesis: two.sided

    Mood two-sample test of scale

data:  pull(filter(BMI_long, Sex == "Women", Year == "1985", Region ==  and pull(filter(BMI_long, Sex == "Women", Year == "1985", Region ==     "Rural"), BMI) and     "Urban"), BMI)
Z = 3.1305, p-value = 0.001745
alternative hypothesis: two.sided

    Mood two-sample test of scale

data:  pull(filter(BMI_long, Sex == "Women", Year == "1985", Region ==  and pull(filter(BMI_long, Sex == "Women", Year == "2017", Region ==     "Rural"), BMI) and     "Rural"), BMI)
Z = -0.24228, p-value = 0.8086
alternative hypothesis: two.sided

    Mood two-sample test of scale

data:  pull(filter(BMI_long, Sex == "Women", Year == "1985", Region ==  and pull(filter(BMI_long, Sex == "Women", Year == "2017", Region ==     "Urban"), BMI) and     "Urban"), BMI)
Z = 1.5317, p-value = 0.1256
alternative hypothesis: two.sided

Our p value is less than .05 for both tests, thus we reject our null hypothesis that there is no difference in the variance. Therefore, we conclude that the variance is not equal and that our data also violates this assumption.

We will perform a special t.test where we account for the fact that our variance is not equal.

Another important consideration is that the data is what we call paired. Meaning the measurements from the rural and urban areas are not independent. That is because we have a rural and urban measurement mean for nearly every country. Thus these values may be more similar to one another if they come from the same country.


    Paired t-test

data:  pull(filter(BMI_long, Sex == "Women", Year == "2017", Region ==  and pull(filter(BMI_long, Sex == "Women", Year == "2017", Region ==     "Rural"), BMI) and     "Urban"), BMI)
t = -10.356, df = 194, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -1.0573625 -0.7190478
sample estimates:
mean of the differences 
             -0.8882051 

    Paired t-test

data:  pull(filter(BMI_long, Sex == "Women", Year == "1985", Region ==  and pull(filter(BMI_long, Sex == "Women", Year == "1985", Region ==     "Rural"), BMI) and     "Urban"), BMI)
t = -14.095, df = 195, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -1.1870263 -0.8956268
sample estimates:
mean of the differences 
              -1.041327 

    Paired t-test

data:  pull(filter(BMI_long, Sex == "Women", Year == "1985", Region ==  and pull(filter(BMI_long, Sex == "Women", Year == "2017", Region ==     "Rural"), BMI) and     "Rural"), BMI)
t = -22.119, df = 195, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -2.591762 -2.167422
sample estimates:
mean of the differences 
              -2.379592 

    Paired t-test

data:  pull(filter(BMI_long, Sex == "Women", Year == "1985", Region ==  and pull(filter(BMI_long, Sex == "Women", Year == "2017", Region ==     "Urban"), BMI) and     "Urban"), BMI)
t = -24.378, df = 198, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -2.383938 -2.027118
sample estimates:
mean of the differences 
              -2.205528 

Question opportunity: Looking at the t value, was global BMI lower in Rural or Urban areas in 1985?

Now we will try transform our data to make it more normally distributed. One way to do this is to take the logarithm of the data values. Then we will see how this influences the results. Again we will focus on the data for women.

# A tibble: 6 x 3
# Groups:   Year [2]
  Year  Region   shapiro_test
  <chr> <chr>           <dbl>
1 1985  National     0.00315 
2 1985  Rural        0.0105  
3 1985  Urban        0.000334
4 2017  National     0.293   
5 2017  Rural        0.0784  
6 2017  Urban        0.00416 
# A tibble: 6 x 3
# Groups:   Year [2]
  Year  Region   shapiro_test
  <chr> <chr>           <dbl>
1 1985  National  0.0000478  
2 1985  Rural     0.000679   
3 1985  Urban     0.000000332
4 2017  National  0.00363    
5 2017  Rural     0.0108     
6 2017  Urban     0.0000130  

The data appears to be more similar to the normal distribution, although not quite. Again, our sample size of 200 is quite large and the t-test is generally quite robust to violations of normality with large n, thus the modified t-test to account for unequal variance might be a good option using the log normalized data, as it is at least more normally distributed.

Let’s see the results of the t-test with the transformed data:


    Paired t-test

data:  pull(filter(BMI_long_log, Sex == "Women", Year == "2017", Region ==  and pull(filter(BMI_long_log, Sex == "Women", Year == "2017", Region ==     "Rural"), log_BMI) and     "Urban"), log_BMI)
t = -10.058, df = 194, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.04242774 -0.02851589
sample estimates:
mean of the differences 
            -0.03547182 

    Paired t-test

data:  pull(filter(BMI_long_log, Sex == "Women", Year == "1985", Region ==  and pull(filter(BMI_long_log, Sex == "Women", Year == "1985", Region ==     "Rural"), log_BMI) and     "Urban"), log_BMI)
t = -13.962, df = 195, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.05214677 -0.03923811
sample estimates:
mean of the differences 
            -0.04569244 

    Paired t-test

data:  pull(filter(BMI_long_log, Sex == "Women", Year == "1985", Region ==  and pull(filter(BMI_long_log, Sex == "Women", Year == "2017", Region ==     "Rural"), log_BMI) and     "Rural"), log_BMI)
t = -22.369, df = 195, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.10617051 -0.08896626
sample estimates:
mean of the differences 
            -0.09756839 

    Paired t-test

data:  pull(filter(BMI_long_log, Sex == "Women", Year == "1985", Region ==  and pull(filter(BMI_long_log, Sex == "Women", Year == "2017", Region ==     "Urban"), log_BMI) and     "Urban"), log_BMI)
t = -23.977, df = 198, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.09377834 -0.07952498
sample estimates:
mean of the differences 
            -0.08665166 

We can see that our results are quite similar to that of the original data, however the t values are slightly smaller. In other cases we may see a much more dramatic influence of transforming our data.

Now, let’s take a look at non parametric tests, which are also a great option when the assumptions of the t-test are violated.

Nonparametric two sample tests

There are two nonparametric options to consider when the assumptions of the t-test are violated. The Wilcoxon signed rank test (for paired data - the alternative is Wilcoxon rank sum test for independent samples) and the Two-sample Kolmogorov-Smirnov test both do not assume normality (has both paired and unpaired methods). Thus these tests should be considered when the data of either groups does not appear to be normally distributed and particularly when the number of samples is low.

Importantly the Kolmogorov-Smirnov (KS) test does not assume normality or equal variance, while the Wilcoxon signed rank test does assume equal variance. Here is how you would perform these tests. However in our case, because the variance is not equal between some of our groups of interest, the Kolmogorov-Smirnov test would be more appropriate. Both the t-test and the KS test evaluate if the distributions of the two groups are identical, however the KS test does not particularly test any aspect of the distribution like the mean, therefore there are no confidence intervals in the output using this test.


    Two-sample Kolmogorov-Smirnov test

data:  pull(filter(BMI_long, Sex == "Women", Year == "2017", Region ==  and pull(filter(BMI_long, Sex == "Women", Year == "2017", Region ==     "Rural"), BMI) and     "Urban"), BMI)
D = 0.20006, p-value = 0.0007385
alternative hypothesis: two-sided

    Two-sample Kolmogorov-Smirnov test

data:  pull(filter(BMI_long, Sex == "Women", Year == "1985", Region ==  and pull(filter(BMI_long, Sex == "Women", Year == "1985", Region ==     "Rural"), BMI) and     "Urban"), BMI)
D = 0.19914, p-value = 0.0007779
alternative hypothesis: two-sided

What about the difference in female BMI from 1985 to 2017 for both regions? Recall that the variance was equal for these comparisons.


    Wilcoxon signed rank test with continuity correction

data:  pull(filter(BMI_long, Sex == "Women", Year == "1985", Region ==  and pull(filter(BMI_long, Sex == "Women", Year == "2017", Region ==     "Rural"), BMI) and     "Rural"), BMI)
V = 273, p-value < 2.2e-16
alternative hypothesis: true location shift is not equal to 0

    Wilcoxon signed rank test with continuity correction

data:  pull(filter(BMI_long, Sex == "Women", Year == "1985", Region ==  and pull(filter(BMI_long, Sex == "Women", Year == "2017", Region ==     "Urban"), BMI) and     "Urban"), BMI)
V = 189, p-value < 2.2e-16
alternative hypothesis: true location shift is not equal to 0

There is a significant difference across time for both regions, as we saw with the t-test. There is also a significant difference by region for each year. However, the p-values are a bit larger for the KS test results than we saw with the t-test.

Multiple Testing Correction

It’s important to note that ultimately we wanted to test 4 different tests:

  1. Is there a difference in mean BMI for women between Rural and Urban areas in 1985?
  2. Is there a difference in mean BMI for women between Rural and Urban areas in 2017?
  3. Is there a difference in mean BMI for women between 1985 and 2017 in Rural areas?
  4. Is there a difference in mean BMI for women between 1985 and 2017 in Urban areas?

When we test multiple questions like this, we need to correct for the multiple tests that we are performing.

The more we test data, the more likely we are to see a significant finding just by chance.

One way to do this is using the Bonferroni method.

In this method we would divide our significance threshold (generally 0.05) by the number of tests.

[1] 0.0125

Our new significance threshold is now 0.0125. Thus our p-values should be less than this value for us to reject the null that there is no difference in means. In all cases, our p-values were less than 0.0125. So we see a significant difference in the means of the groups after multiple testing correction for our different tests.

Again, it would be reasonable to use the t-test because it is robust to deviations in normality when samples are relatively large. We can see that we obtained the same results regardless of the test that we used. However, if sample sizes are small (generally speaking n<15 for each group), then these nonparametric options are useful to know.

The D values in the output of our KS tests, show the magnitude of distance in the difference between the distributions of the groups tested. You may notice that the D value is larger for the tests of BMI across time rather then across region. In these tests the p-value was also smaller.

Data Visualization

Again we will utilize ggplot2 to create plots to look at the directional and magnitude of the differences in BMI we are interested in. If you need additional information please see here. The top two lines of the code for the following plots, filter the data to only specific values of interest. Then we layer what is called a jitter on top of a box plot. A jitter is essentially a dot plot but with some variation on the location of the points so that they do not line up vertically which can make the individual points difficult to see.

Let’s look at the national mean BMI estimates for each of the years:

Now Let’s look at the change in rural and urban mean BMI estimates:

Let’s put the plots together to see how the change over the years differs between the regions. We will use again use facet_wrap() to do this:

Indeed the change in BMI over time looks bigger in the rural areas!

How do the different countries compare? Or in other words what do the individual dots represent in our box plots? We will take a look using geom_label():

If we include all country names this is a bit too much… so perhaps we should focus on just the extreme BMI values using filter() function of thedplyr package. We will also use the ggrepel package to have our labels not overlap each other.

And let’s fill the box plots with color and outline in black:

Overall differences

Let’s take a look at all the data together:

That’s useful, but let’s look at the individual points and include our country labels, to do so lets change our United States of America label to USA:

BMI_long$Country <-BMI_long$Country %>%
  str_replace( pattern = "United States of America", replacement = "USA")


ggplot(BMI_long, aes(x = Year, y = BMI, col = Year)) + 
  geom_boxplot(outlier.shape = NA, color = "black" , aes(fill = Year)) + 
  facet_grid(~ Sex + Region) + 
  geom_hline(yintercept=30, linetype="dashed", color = "red", size =1) + 
  # This will add a horizontal dashed line to indicate the obesity BMI threshold
  geom_jitter(data=subset(BMI_long), 
              aes(x =Year, y =BMI), 
              width = .2, size =2, shape =21, color = "black", fill = "gray") + 
  # This will add the individual country data points
  # The shape 21 allows for a different fill and outline color
  # The width determines how wide the jitter points are plotted
  geom_jitter(data=subset(BMI_long, Country == "USA"), 
              aes(x =Year, y =BMI), 
              width = .02, size =12, shape =21, color = "black", fill = "gray") + 
  # This will add points that are larger for the USA data
  geom_text(data=subset(BMI_long,  Country == "USA"), 
            aes(x =Year, y =BMI,label=Country), 
            color = "black") + 
  # This will add USA labels to the USA points
  theme(legend.position = "none", 
  # This is useful for removing the legend
        axis.text.x = element_text(size = 15,angle = 30), 
        # this changes the size and angle of the x axis point labels 
        axis.text.y = element_text(size = 20), 
        axis.title.y = element_text(size =15), 
        axis.title.x = element_text(size =15), 
        strip.text.x = element_text(size = 15)) +
  # This changes the size of x axis labels for the facet 
        ggtitle( "Differences in BMI Over Time and Across Region Type and Gender") 

Here we can see that overall BMI appears to be increasing globally over time. Additionally we can see that this is occurring not just in urban areas, but also in rural areas. The US is consistently above the median in all strata of the data. In general, the female data shows higher BMI values than the male data. The rural USA BMI appears to be higher than the urban BMI for both men and women. Many countries have average BMI estimates above the obesity threshold of 30. Thus it appears that education and outreach programs for weight management should focus on both rural and urban areas and both genders. Education and assistance for women may be especially helpful.

Differences in rate of change in BMI

How does the rate of change in BMI differ between groups? Which group might especially need attention?

First let’s calculate the differences in BMI from 2017 and 1985 and add this to our BMI_long data object:

# A tibble: 6 x 4
  Country     Sex   Type             Difference
  <chr>       <chr> <chr>                 <dbl>
1 Afghanistan Men   Rural_difference     2.8   
2 Afghanistan Women Rural_difference     3.5   
3 Albania     Men   Rural_difference     1.90  
4 Albania     Women Rural_difference     0.1000
5 Algeria     Men   Rural_difference     3     
6 Algeria     Women Rural_difference     3.70  

Let’s replace “United states of America” with “USA” and make a plot with this data to compare the change in BMI:

We can now see that the rate of change from 1985 to 2017 appears to be larger in the women compared to the men in all regions. The group with the largest increase in the USA is the women living in rural areas.

Let’s check the difference with some statistical tests:

# A tibble: 1,200 x 4
   Country        Sex   Type                Difference
   <chr>          <chr> <chr>                    <dbl>
 1 Greece         Women Rural_difference        -1.5  
 2 Greece         Women National_difference     -1.3  
 3 Greece         Women Urban_difference        -1.20 
 4 Italy          Women Rural_difference        -1.10 
 5 Czech Republic Women Rural_difference        -0.8  
 6 Spain          Women Rural_difference        -0.800
 7 Lithuania      Women Urban_difference        -0.700
 8 Spain          Women Urban_difference        -0.700
 9 Lithuania      Women National_difference     -0.700
10 Spain          Women National_difference     -0.700
# … with 1,190 more rows


    Mood two-sample test of scale

data:  pull(filter(BMI_diff_long, Sex == "Women", Type == "Rural_difference"),  and pull(filter(BMI_diff_long, Sex == "Women", Type == "Urban_difference"),     Difference) and     Difference)
Z = 3.5379, p-value = 0.0004033
alternative hypothesis: two.sided

    Mood two-sample test of scale

data:  pull(filter(BMI_diff_long, Sex == "Men", Type == "Rural_difference"),  and pull(filter(BMI_diff_long, Sex == "Men", Type == "Urban_difference"),     Difference) and     Difference)
Z = 0.59121, p-value = 0.5544
alternative hypothesis: two.sided

    Mood two-sample test of scale

data:  pull(filter(BMI_diff_long, Sex == "Women", Type == "Rural_difference"),  and pull(filter(BMI_diff_long, Sex == "Men", Type == "Rural_difference"),     Difference) and     Difference)
Z = 10.843, p-value < 2.2e-16
alternative hypothesis: two.sided

    Two-sample Kolmogorov-Smirnov test

data:  pull(filter(BMI_diff_long, Sex == "Women", Type == "Rural_difference"),  and pull(filter(BMI_diff_long, Sex == "Women", Type == "Urban_difference"),     Difference) and     Difference)
D = 0.16534, p-value = 0.009043
alternative hypothesis: two-sided

    Two-sample Kolmogorov-Smirnov test

data:  pull(filter(BMI_diff_long, Sex == "Men", Type == "Rural_difference"),  and pull(filter(BMI_diff_long, Sex == "Men", Type == "Urban_difference"),     Difference) and     Difference)
D = 0.14586, p-value = 0.02995
alternative hypothesis: two-sided

    Two-sample Kolmogorov-Smirnov test

data:  pull(filter(BMI_diff_long, Sex == "Men", Type == "Rural_difference"),  and pull(filter(BMI_diff_long, Sex == "Women", Type == "Rural_difference"),     Difference) and     Difference)
D = 0.35204, p-value = 5.645e-11
alternative hypothesis: two-sided

Now we have performed seven comparisons (4 earlier) so we should apply our multiple testing correction

[1] 0.007142857

We see that there is a significant difference in the change in BMI Rural communities between men and women. This change is larger for women.

Importantly- we noticed that it appears to be specific countries where BMI shows a particular increase especially for women. Which countries are those? how does that compare with the US? Clearly the US is among the countries with the highest differences.

# A tibble: 6 x 4
  Country Sex   Type                Difference
  <chr>   <chr> <chr>                    <dbl>
1 USA     Men   Rural_difference          3.10
2 USA     Women Rural_difference          3.5 
3 USA     Men   Urban_difference          3.1 
4 USA     Women Urban_difference          3.40
5 USA     Men   National_difference       3.10
6 USA     Women National_difference       3.4 

In the US, focus should be placed on both urban and rural women to improve this public health issue.

Here we can see the countries have the largest differences in BMI from 1985-2017:

# A tibble: 6 x 4
  Country     Sex   Type                Difference
  <chr>       <chr> <chr>                    <dbl>
1 Egypt       Women Rural_difference          5.9 
2 Honduras    Women National_difference       5.60
3 Honduras    Women Rural_difference          5.5 
4 Egypt       Women National_difference       5.10
5 Saint Lucia Women Rural_difference          5   
6 Honduras    Women Urban_difference          4.9 

However it is important to see what the mean BMI values are were for these countries in 2017. It could be that the average was underweight in 1985… let’s take a look.

# A tibble: 9 x 5
  Country     Sex   Region   Year    BMI
  <chr>       <chr> <chr>    <chr> <dbl>
1 Egypt       Women Urban    2017   32.3
2 Egypt       Women National 2017   31.7
3 Egypt       Women Rural    2017   31.3
4 Saint Lucia Women National 2017   30.5
5 Saint Lucia Women Rural    2017   30.5
6 Saint Lucia Women Urban    2017   30.5
7 Honduras    Women Urban    2017   28.3
8 Honduras    Women National 2017   27.7
9 Honduras    Women Rural    2017   26.9
# A tibble: 6 x 4
  Country Sex   Type                Difference
  <chr>   <chr> <chr>                    <dbl>
1 Egypt   Women Rural_difference          5.9 
2 Egypt   Women National_difference       5.10
3 Egypt   Women Urban_difference          4.20
4 Egypt   Men   Urban_difference          2.60
5 Egypt   Men   Rural_difference          2.5 
6 Egypt   Men   National_difference       2.5 

Thus rural women in Egypt had the greatest increase in BMI from 1985 to 2017 in this data (5.9) and the average BMI is now over the obesity threshold of 30.

The data suggests that rural women in Egypt and other countries may especially benefit from dietary resources and our interventions and programs to assist with weight management.

Now let’s make a plot that summarizes our findings. To do this we will simplify the other plots we made and then combine them together.

# simplified national means plot
Means_plot<-BMI_long %>% 
  filter(Sex %in% c("Men", "Women"), 
         Year %in% c("1985", "2017"), 
         Region == "National") %>%
ggplot(aes(x = Sex, y = BMI)) + 
  geom_boxplot(outlier.shape = NA, color = "black" , aes(fill = Sex)) + 
 scale_fill_manual(values=c("dodgerblue", "orchid2")) +
  facet_grid(~ Year) + 
  geom_hline(yintercept=30, linetype="dashed", color = "red", size =1) + 
  geom_jitter(data=BMI_long %>%
                filter(Sex %in% c("Men", "Women"), 
                       Year %in% c("1985", "2017"), 
                       Region == "National"),
                aes(x =Sex, y =BMI), 
                width = .2, size =2, shape =21, 
                color = "black", fill = "gray") +
  geom_jitter(data=subset(BMI_long %>%
                            filter(Sex %in% c("Men", "Women"), 
                                   Year %in% c("1985", "2017"), 
                                   Region == "National", 
                                   Country == "USA")), 
                             aes(x =Sex, y =BMI), 
                             width = .02, size =12, shape =21, 
                             color = "black", fill = "gray") + 
  # This will add points that are larger for the USA data
  geom_text(data=subset(BMI_long%>%
                          filter(Sex %in% c("Men", "Women"), 
                                 Year %in% c("1985", "2017"), 
                                 Region == "National", Country == "USA")),
                          aes(x =Sex, y =BMI,label=Country), 
                          color = "black") + 
  # This will add USA labels to the USA points
  theme_linedraw() +
  # This will make thebackground of the plot white and the facet labels black
  theme(legend.position = "none", 
  # This is useful for removing the legend
        axis.text.x = element_text(size = 15,angle = 30, vjust = 0.5), 
        # this changes the size and angle of the x axis point labels 
        axis.text.y = element_text(size = 20), 
        axis.title.y = element_text(size =15), 
        axis.title.x = element_text(size =15), 
        strip.text.x = element_text(size = 15))
   
#Simplified difference plot 
BMI_diff_long$Type <-BMI_diff_long$Type %>%
  str_replace( pattern = "_difference", replacement = "")

Diff_plot<-BMI_diff_long %>% 
  filter(Sex %in% c("Men", "Women"), 
         Type != "National") %>%
ggplot( aes(x = Type, y = Difference, col = Type)) + 
  geom_boxplot(outlier.shape = NA, color = "black" , aes(fill = Sex)) + 
  scale_fill_manual(values=c("dodgerblue", "orchid2")) +
  facet_grid(~ Sex) +
  geom_jitter(data=BMI_diff_long %>% 
    filter(Sex %in% c("Men", "Women"), 
           Type != "National"), 
    aes(x =Type, y =Difference), 
    width = .2, size =2, shape =21, 
    color = "black", fill = "gray") + 
  geom_jitter(data=subset(BMI_diff_long %>% 
    filter(Sex %in% c("Men", "Women"), 
           Type != "National", 
           Country == "USA")), 
    aes(x =Type, y =Difference), 
    width = .02, size =12, shape =21, 
    color = "black", fill = "gray") + 
  # This will add points that are larger for the USA data
  geom_text(data=subset(BMI_diff_long %>% 
    filter(Sex %in% c("Men", "Women"),
           Type != "National"), 
           Country == "USA"),
    aes(x =Type, y =Difference,label=Country), 
    color = "black") + 
  # This will add USA labels to the USA points
  theme_linedraw() +
    # This will make the background of the plot white and the facet labels black
  theme(legend.position = "none", 
  # This is useful for removing the legend
        axis.text.x = element_text(size = 15,angle = 30, vjust = 0.5), 
        # this changes the size and angle of the x axis point labels 
        axis.text.y = element_text(size = 20), 
        axis.title.y = element_text(size =15), 
        axis.title.x = element_text(size =15), 
        strip.text.x = element_text(size = 15))
  # this changes the size of x axis labels for the facet

#add labels
Diff_plot<-Diff_plot + 
        labs(title = "Change in BMI by region", 
             x = "", 
             y = "Change in BMI \n (1985 to 2017)") +
        theme(title = element_text (size = 12, face = "bold"))

Means_plot <-Means_plot + 
        labs(title = "Mean BMI over time", 
             x = "", 
             y = "Mean BMI") +
        theme(title = element_text (size = 12, face = "bold"))



obesity_text<-tibble(Year=c(1985),BMI=c(31),Sex=c("Men"),label=c("Obesity"))

Means_plot <-Means_plot + 
             geom_text(data = obesity_text,
                       label=pull(obesity_text,label), 
                       color = "red", 
                       aes( fontface ="bold.italic", size = 13))

cowplot::plot_grid(Means_plot, Diff_plot, labels = c("A", "B"))

Great, now we have put two plots together using the plot_grid() function of the cowplot package. This way we can clearly communicate two messages. The first being that BMI has increased over time globally and that many countries including the United States of America are approaching a mean BMI that is above the obesity threshold of 30. We can also see that women on average have larger BMI values than males, but that both genders show increased levels over time. In the second plot we can see that the increase in BMI is not just happening in urban communities, but in both rural and urban communities and particularly in women.

Summary

We have evaluated BMI average estimates from 200 different countries around the world. To do so we imported data from a pdf using the pdftools package. We used tidyverse packages such as dplyr, stringr, and tidy to clean the data and get it in a workable format. Our statistical analysis focused on evaluating differences in BMI in females around the world across time and between rural and urban areas. We found a significant difference both between years and between the type of community among women globally using t-tests and nonparametric tests. Thus BMI has increased in women since 1985. Although BMI estimates are significantly higher in Urban areas compared to rural areas, BMI estimates have increased in both regions. We learned that there are assumptions and considerations to keep in mind when performing tests that compare two groups.

We learned that the t-test relies on: 1) normality of the data for both groups (this is not as much of an issue if the number of observations is relatively large total n>30) 2) equal variance between the two groups (make sure you do the correct test if the data is not normal) 3) balanced sample sizes of the two groups

We learned that we can evaluate if our data is normally distributed by plotting the distribution and by creating Q-Q plots.

We learned that if our data is not normally distributed, we can consider these options: 1) We can still perform a t-test if our n is large 2) We can transform the data before performing a t-test 3) We can use a nonparametric test (Wilcoxon signed rank test and the Two-sample Kolmogorov-Smirnov (KS) test)

We learned that if our groups do not have equal variance, that we need to use a modified t-test to account for this or the correct nonparametric test that does not rely on this assumption (Two-sample Kolmogorov-Smirnov test).

We also learned that if our groups are not well balanced, that we can consider resampling methods.

Finally its also important to remember that when we have paired data and intend to compare means, we should perform a paired test (paired t-test, Wilcoxon signed rank test, or paired KS test). Our data used in this case study was paired because observations were taken for the same countries for different categories of populations - thus, we wanted to compare these populations within the same country (male vs female, rural vs urban etc.). Other examples would be in a case-control study (if samples are matched for various demographics) or a study with repeated measures (for example, symptom measures from the same individual before and after a treatment).

Using the ggplot2 package we were able to visualize trends in the data. Importantly, the largest increase appears to be in the rural areas particularly for women. We were also able to identify how the US compared to other countries and which countries showed the largest increase in BMI over time. Analyses like this are important for defining which groups could benefit the most from interventions, education, and policy changes when attempting to mitigate public health challenges. You can see in the article that this data came from that many additional considerations would be involved to perform such an analysis.

Suggested Homework

Students can evaluate the change in BMI over time using the global data available for each year between 2015 and 2017. This data can be found here.

LS0tCnRpdGxlOiAiT3BlbiBDYXNlIFN0dWRpZXMgLSBSdXJhbCBhbmQgVXJiYW4gT2Jlc2l0eSIKY3NzOiBzdHlsZS5jc3MKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBzZWxmX2NvbnRhaW5lZDogeWVzCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIG51bWJlcl9zZWN0aW9uczogbm8KICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICB3b3JkX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKLS0tCgoKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoaW5jbHVkZSA9IFRSVUUsIGNvbW1lbnQgPSBOQSwgZWNobyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSkKYGBgCgpgYGB7ciwgZWNobyA9IEZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJtYWlucGxvdC5wbmciKSkKYGBgCgojIyBNb3RpdmF0aW9uCltCTUldKGh0dHBzOi8vd3d3LmNkYy5nb3YvaGVhbHRoeXdlaWdodC9hc3Nlc3NpbmcvYm1pL2FkdWx0X2JtaS9pbmRleC5odG1sKSBpcyB1c2VkIGFzIGEgcHJveHkgZm9yIGFkaXBvc2l0eSBhbmQgaXMgbWVhc3VyZWQgYXMgYW4gaW5kaXZpZHVhbCdzIHdlaWdodCBpbiBraWxvZ3JhbXMgZGl2aWRlZCBieSB0aGUgaW5kaXZpZHVhbCdzIGhlaWdodCBpbiBtZXRlcnMgc3F1YXJlZC4gRGlmZmVyZW50IGNhdGVnb3JpZXMgb2Ygd2VpZ2h0IGFyZSBkZWZpbmVkIHdpdGggdGhlIGZvbGxvd2luZyBjdXRvZmZzIGFzIGRlZmluZWQgYnkgdGhlIFtXb3JsZCBIZWFsdGggT3JnYW5pemF0aW9uXShodHRwOi8vd3d3LmV1cm8ud2hvLmludC9lbi9oZWFsdGgtdG9waWNzL2Rpc2Vhc2UtcHJldmVudGlvbi9udXRyaXRpb24vYS1oZWFsdGh5LWxpZmVzdHlsZS9ib2R5LW1hc3MtaW5kZXgtYm1pKSBbQ2VudGVycyBmb3IgRGlzZWFzZSBDb250cm9sIGFuZCBQcmV2ZW50aW9uXShodHRwczovL3d3dy5jZGMuZ292L29iZXNpdHkvYWR1bHQvZGVmaW5pbmcuaHRtbCkgYW5kIHRoZSBbTmF0aW9uYWwgSW5zdGl0dXRlcyBvZiBIZWFsdGhdKGh0dHBzOi8vd3d3Lm5obGJpLm5paC5nb3Yvc2l0ZXMvZGVmYXVsdC9maWxlcy9tZWRpYS9kb2NzL29iZXNpdHktZXZpZGVuY2UtcmV2aWV3LnBkZik6CgohW10oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9ib29rcy9OQks1MzU0NTYvYmluL2JtaV9XSE8uanBnKQoKIyMjIyMjIFtCTUkgdGFibGVdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvYm9va3MvTkJLNTM1NDU2L2Jpbi9ibWlfV0hPLmpwZykKClRoZSBmb2xsb3dpbmcgY2hhcnQgY2FuIGhlbHAgeW91IGlkZW50aWZ5IHlvdXIgQk1JIGVzdGltYXRlOgohW10oaHR0cDovL2NvbnRlbnQuZXZlcnlkYXloZWFsdGguY29tL21heW9kaWV0L2ltYWdlcy9CTUktY2hhcnQuanBnKQoKIyMjIyMjIFtCTUkgQ2hhcnRdKGh0dHA6Ly9kaWV0Lm1heW9jbGluaWMub3JnL2RpZXQvZWF0L3doYXQtaXMteW91ci1ibWk/eGlkPW5sX01heW9DbGluaWNEaWV0XzIwMTYwNDI2KSAKCkhpZ2ggQk1JICg+MzApIGlzIGFzc29jaWF0ZWQgd2l0aCBoaWdoZXIgcmF0ZXMgb2YgYWxsLWNhdXNlcyBvZiBtb3J0YWxpdHksIGFzIHdlbGwgYXMgaW5jcmVhc2VkIHJhdGVzIG9mIHR5cGUgMiBkaWFiZXRlcywgY2FuY2VyLCBoZWFydCBkaXNlYXNlLCBhbmQgc3Ryb2tlLiBGb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBzZWUgW2hlcmVdKGh0dHBzOi8vd3d3Lm5obGJpLm5paC5nb3Yvc2l0ZXMvZGVmYXVsdC9maWxlcy9tZWRpYS9kb2NzL29iZXNpdHktZXZpZGVuY2UtcmV2aWV3LnBkZikuCgoKQW4gW2FydGljbGVdKGh0dHBzOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvczQxNTg2LTAxOS0xMTcxLXgucGRmKSBwdWJsaXNoZWQgaW4gKk5hdHVyZSogZXZhbHVhdGVkIGFuZCBjb21wYXJlZCB0aGUgQm9keS1NYXNzIEluZGV4IChCTUkpIG9mIHBvcHVsYXRpb25zIGluIHJ1cmFsIGFuZCB1cmJhbiBjb21tdW5pdGllcyBhcm91bmQgdGhlIHdvcmxkOiAKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iMTAwJSIsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkoaGVyZSkKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgicGFwZXIucG5nIikpCgpgYGAKCiMjIyMgey5yZWZlcmVuY2VfYmxvY2t9Ck5DRCBSaXNrIEZhY3RvciBDb2xsYWJvcmF0aW9uwqAoTkNELVJpc0MpLiBSaXNpbmcgcnVyYWwgYm9keS1tYXNzIGluZGV4IGlzIHRoZSBtYWluIGRyaXZlciBvZiB0aGUgZ2xvYmFsIG9iZXNpdHkgZXBpZGVtaWMgaW4gYWR1bHRzLiAqTmF0dXJlKiA1NjksIDI2MOKAkzI2NCAoMjAxOSkuIAoKIyMjIwpUaGlzIGFydGljbGUgY2hhbGxlbmdlZCB0aGUgd2lkZWx5LWhlbGQgdmlldyB0aGF0IGluY3JlYXNlZCB1cmJhbml6YXRpb24gd2FzIG9uZSBvZiB0aGUgbWFqb3IgcmVhc29ucyBmb3IgaW5jcmVhc2VkIGdsb2JhbCBvYmVzaXR5IHJhdGVzLiBUaGlzIHZpZXcgY2FtZSBhYm91dCBiZWNhdXNlIG1hbnkgY291bnRyaWVzIGFyb3VuZCB0aGUgd29ybGQgaGF2ZSBzaG93biBpbmNyZWFzZWQgdXJiYW5pemF0aW9uIGxldmVscyBpbiBwYXJhbGxlbCB3aXRoIGluY3JlYXNlZCBvYmVzaXR5IHJhdGVzLiBIb3dldmVyIHRoaXMgc3R1ZHkgZGVtb25zdHJhdGVkIHRoYXQgdGhpcyBtaWdodCBub3QgYmUgdGhlIGNhc2U7IGFuZCB0aGF0IGluIGZhY3QgZm9yIG1vc3QgcmVnaW9ucyBhcm91bmQgdGhlIHdvcmxkLCBCTUkgbWVhc3VyZW1lbnRzIGFyZSBpbmNyZWFzaW5nIGluIHJ1cmFsIHBvcHVsYXRpb25zIGp1c3QgYXMgbXVjaCBpZiBub3QgbW9yZSBzbyB0aGFuIHVyYmFuIHBvcHVsYXRpb25zLiBUaGlzIGNhc2Ugc3R1ZHkgd2lsbCBldmFsdWF0ZSB0aGUgZGF0YSByZXBvcnRlZCBpbiB0aGlzIGFydGljbGUgdG8gZXhwbG9yZSByZWdpb25hbCBhbmQgZ2VuZGVyIHNwZWNpZmljIGRpZmZlcmVuY2VzIGluIHRoZSBvYmVzaXR5IHJhdGVzIGFyb3VuZCB0aGUgd29ybGQgaW4gMTk4NSBhbmQgMjAxNy4gTW9zdCBpbXBvcnRhbnRseSB3ZSB3aWxsIHRlc3QgaWYgdGhlcmUgaXMgYSBkaWZmZXJlbmNlIGluIG9iZXNpdHkgcmF0ZXMgYmV0d2VlbiBydXJhbCBhbmQgdXJiYW4gY29tbXVuaXRpZXMuIFRvIGRvIHRoaXMgd2Ugd2lsbCB0ZXN0IGlmIHRoZXJlIGlzIGEgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBtZWFucyBvZiB0aGUgbWVhc3VyZW1lbnRzIGZvciBlYWNoIGdyb3VwLgoKPGI+PHU+IE91ciBtYWluIHF1ZXN0aW9ucyBhcmU6IDwvdT48L2I+CgoxKSBJcyB0aGVyZSBhIGRpZmZlcmVuY2UgYmV0d2VlbiBydXJhbCBhbmQgdXJiYW4gQk1JIGVzdGltYXRlcyBhcm91bmQgdGhlIHdvcmxkPyBIb3cgZG9lcyB0aGlzIGNvbXBhcmUgZm9yIG1hbGVzIGFuZCBmZW1hbGVzPwoyKSBIb3cgaGF2ZSBCTUkgZXN0aW1hdGVzIGNoYW5nZWQgZnJvbSAxOTg1IHRvIDIwMTc/CjMpIEhvdyBkbyBkaWZmZXJlbnQgY291bnRyaWVzIGNvbXBhcmUgZm9yIEJNSSBlc3RpbWF0ZXMtIGluIHBhcnRpY3VsYXIsIGhvdyBkb2VzIHRoZSBVbml0ZWQgU3RhdGVzIGNvbXBhcmUgdG8gdGhlIHJlc3Qgb2YgdGhlIHdvcmxkPwoKSW4gdGhpcyBjYXNlIHN0dWR5LCB3ZeKAmWxsIHdhbGsgeW91IHRocm91Z2ggaW1wb3J0aW5nIGRhdGEgZnJvbSBhIHBkZiwgY2xlYW5pbmcgZGF0YSwgd3JhbmdsaW5nIGRhdGEsIHZpc3VhbGl6aW5nIHRoZSBkYXRhLCBhbmQgY29tcGFyaW5nIHRoZSBtZWFucyBvZiB0d28gZ3JvdXBzIHVzaW5nIHdlbGwtZXN0YWJsaXNoZWQgYW5kIGNvbW1vbmx5IHVzZWQgcGFja2FnZXMsIGluY2x1ZGluZyBgc3RyaW5ncmAsIGB0aWR5cmAsIGBkcGx5cmAsIGBwdXJycmAsIGFuZCBgZ2dwbG90MmAuIFdlIHdpbGwgZXNwZWNpYWxseSBmb2N1cyBvbiB1c2luZyBwYWNrYWdlcyBhbmQgZnVuY3Rpb25zIGZyb20gdGhlIFtUaWR5dmVyc2VdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvKS4gVGhlIFRpZHl2ZXJzZSBpcyBhIGxpYnJhcnkgb2YgcGFja2FnZXMgY3JlYXRlZCBieSB0aGUgY2hpZWYgc2NpZW50aXN0IGF0IFJTdHVkaW8sIEhhZGxleSBXaWNraGFtLiBXaGlsZSBzb21lIHN0dWRlbnRzIG1heSBiZSBmYW1pbGlhciB3aXRoIHByZXZpb3VzIFIgcHJvZ3JhbW1pbmcgcGFja2FnZXMsIHRoZXNlIHBhY2thZ2VzIG1ha2UgZGF0YSBzY2llbmNlIGluIFIgZXNwZWNpYWxseSBlZmZpY2llbnQuCgpgYGB7ciwgb3V0LndpZHRoID0gIjIwJSIsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIn0KbGlicmFyeShrbml0cikKaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly90aWR5dmVyc2UudGlkeXZlcnNlLm9yZy9sb2dvLnBuZyIpCmBgYAoKCgpXZSB3aWxsIGJlZ2luIGJ5IGxvYWRpbmcgdGhlIHBhY2thZ2VzIHRoYXQgd2Ugd2lsbCBuZWVkOgpgYGB7cn0KbGlicmFyeShoZXJlKQpsaWJyYXJ5KHBkZnRvb2xzKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KGdsdWUpCmxpYnJhcnkocHVycnIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGNvd3Bsb3QpCmBgYAoKCiBQYWNrYWdlICAgfCBVc2UgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCi0tLS0tLS0tLS0gfC0tLS0tLS0tLS0tLS0KW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2hlcmVfaGVyZSkgICAgICAgfCB0byBlYXNpbHkgbG9hZCBhbmQgc2F2ZSBkYXRhCltwZGZ0b29sc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3BkZnRvb2xzL3BkZnRvb2xzLnBkZikgICB8IHRvIHJlYWQgYSBwZGYgaW50byBSICAgCltzdHJpbmdyXShodHRwczovL3N0cmluZ3IudGlkeXZlcnNlLm9yZy9hcnRpY2xlcy9zdHJpbmdyLmh0bWwpICAgIHwgdG8gbWFuaXB1bGF0ZSB0aGUgdGV4dCB3aXRoaW4gdGhlIHBkZiBvZiB0aGUgZGF0YSAKW3JlYWRyXShodHRwczovL3JlYWRyLnRpZHl2ZXJzZS5vcmcvKSAgICAgIHwgdG8gbWFuaXB1bGF0ZSB0aGUgdGV4dCB3aXRoaW4gdGhlIHBkZiBvZiB0aGUgZGF0YSBpbnRvIGluZGl2aWR1YWwgbGluZXMgIApbZHBseXJdKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy8pICAgICAgfCB0byBhcnJhbmdlL2ZpbHRlci9zZWxlY3Qgc3Vic2V0cyBvZiB0aGUgZGF0YSAKW3RpYmJsZV0oaHR0cHM6Ly90aWJibGUudGlkeXZlcnNlLm9yZy8pICAgICB8IHRvIGNyZWF0ZSBkYXRhIG9iamVjdHMgdGhhdCB3ZSBjYW4gbWFuaXB1bGF0ZSB3aXRoIGRwbHlyL3N0cmluZ3IvdGlkeXIvcHVycnIKW21hZ3JpdHRyXShodHRwczovL21hZ3JpdHRyLnRpZHl2ZXJzZS5vcmcvYXJ0aWNsZXMvbWFncml0dHIuaHRtbCkgICB8IHRvIHVzZSB0aGUgYCU8PiVgIHBpcHBpbmcgb3BlcmF0b3IKW2dsdWVdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvYmxvZy8yMDE3LzEwL2dsdWUtMS4yLjAvKSAgfCB0byBwYXN0ZSBvciBjb21iaW5lIGNoYXJhY3RlciBzdHJpbmdzIGFuZCBkYXRhIHRvZ2V0aGVyCltwdXJycl0oaHR0cHM6Ly9wdXJyci50aWR5dmVyc2Uub3JnLykgICAgICB8IHRvIHBlcmZvcm0gZnVuY3Rpb25zIG9uIGFsbCBjb2x1bW5zIG9mIGEgdGliYmxlClt0aWR5cl0oaHR0cHM6Ly90aWR5ci50aWR5dmVyc2Uub3JnLykgICAgICB8IHRvIGNvbnZlcnQgZGF0YSBmcm9tIHdpZGUgdG8gbG9uZyBmb3JtYXQKW2dncGxvdDJdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLykgICAgfCB0byBtYWtlIHZpc3VhbGl6YXRpb25zIHdpdGggbXVsdGlwbGUgbGF5ZXJzCltnZ3JlcGVsXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ2dyZXBlbC92aWduZXR0ZXMvZ2dyZXBlbC5odG1sKSAgICB8IHRvIGFsbG93IGxhYmVscyBpbiBmaWd1cmVzIG5vdCB0byBvdmVybGFwCltjb3dwbG90XShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvY293cGxvdC92aWduZXR0ZXMvaW50cm9kdWN0aW9uLmh0bWwpIHwgdG8gYWxsb3cgcGxvdHMgdG8gYmUgY29tYmluZWQKX19fCgpUaGUgZmlyc3QgdGltZSB3ZSB1c2UgYSBmdW5jdGlvbiwgd2Ugd2lsbCB1c2UgdGhlIGA6OmAgdG8gaW5kaWNhdGUgd2hpY2ggcGFja2FnZSB3ZSBhcmUgdXNpbmcuIFVubGVzcyB3ZSBoYXZlIG92ZXJsYXBwaW5nIGZ1bmN0aW9uIG5hbWVzLCB0aGlzIGlzIG5vdCBuZWNlc3NhcnksIGJ1dCB3ZSB3aWxsIGluY2x1ZGUgaXQgaGVyZSB0byBiZSBpbmZvcm1hdGl2ZSBhYm91dCB3aGVyZSB0aGUgZnVuY3Rpb25zIHdlIHdpbGwgdXNlIGNvbWUgZnJvbS4KCgojIyMgQ29udGV4dAoKVGhlIG1lYXN1cmVtZW50IG9mIEJNSSBoYXMgc29tZSBbbGltaXRhdGlvbnNdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzQ4OTA4NDEvcGRmL250LTUwLTExNy5wZGYpIHRoYXQgYXJlIHdlbGwgcmVjb2duaXplZCwgYXMgaXQgZG9lcyBub3QgYWNjb3VudCBmb3IgdGhlIGNvbXBvc2l0aW9uIG9mIGJvZHkgbWFzcywgdGhlIGxvY2F0aW9uIG9mIGJvZHkgZmF0LCBvciB0aGUgY29udHJpYnV0aW9uIG9mIGJvZHkgZnJhbWUgc2l6ZS4gSG93ZXZlciwgW0JNSSBoYXMgYmVlbiBhIHVzZWZ1bCBoZWFsdGggaW5kaWNhdG9yXShodHRwczovL2pvdXJuYWxzLmx3dy5jb20vYWNzbS1oZWFsdGhmaXRuZXNzL0Z1bGx0ZXh0LzIwMTYvMDcwMDAvVEhFX0JFTkVGSVRTX09GX0JPRFlfTUFTU19JTkRFWF9BTkRfV0FJU1QuOC5hc3B4I3BkZi1saW5rKSBmb3IgcmlzayBmb3IgbWFueSBkaXNlYXNlcyBhbmQgY29uZGl0aW9ucyBwYXJ0aWN1bGFybHkgd2hlbiBjb21iaW5lZCB3aXRoIG90aGVyIHJpc2sgZmFjdG9yIGluZm9ybWF0aW9uLgoKIyMgV2hhdCBhcmUgdGhlIGRhdGE/CgpXZSB3aWxsIGJlIHVzaW5nIGRhdGEgbG9jYXRlZCB3aXRoaW4gYSB0YWJsZSBvZiB0aGUgW3N1cHBsZW1lbnRhcnkgbWF0ZXJpYWxdKGh0dHBzOi8vc3RhdGljLWNvbnRlbnQuc3ByaW5nZXIuY29tL2VzbS9hcnQlM0ExMC4xMDM4JTJGczQxNTg2LTAxOS0xMTcxLXgvTWVkaWFPYmplY3RzLzQxNTg2XzIwMTlfMTE3MV9NT0VTTTFfRVNNLnBkZikgZm9yIHRoZSBOQ0QtUmlzQyBwYXBlciByZWZlcmVuY2VkIGFib3ZlLiBUaGlzIGlzIGEgcGRmIHRoYXQgY2FuIGJlIGZvdW5kIGZyZWVseSBhdmFpbGFibGUgb25saW5lLgoKCmBgYHtyLCBlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImZpcnN0X3BhZ2UucG5nIikpCmBgYAoKSGVyZSB5b3UgY2FuIHNlZSB0aGF0IHRoZSBkYXRhIGNvbnRhaW5zIG1lYW4gQk1JIHZhbHVlcyBmb3IgYm90aCBtZW4gYW5kIHdvbWVuIGluIHZhcmlvdXMgY291bnRyaWVzIGF0IHRoZSBuYXRpb25hbCBsZXZlbCwgYXMgd2VsbCBhcyB0aGUgbWVhbiBCTUkgdmFsdWVzIGZvciB0aGUgcnVyYWwgYW5kIHVyYmFuIGFyZWFzIG9mIHRoZXNlIGNvdW50cmllcyBmb3IgYm90aCAxOTg1IGFuZCAyMDE3LgoKVGhlIGRhdGEgd2l0aGluIHRoZSBwYXJlbnRoZXNlcyBhcmUgdGhlIDk1ICUgPGI+Y3JlZGlibGUgaW50ZXJ2YWw8L2I+IChDSXMpIHJhbmdlcyBmb3IgdGhlIG1lYW4gQk1JIGVzdGltYXRlcy4gVGhlIGF1dGhvcnMgcHJvdmlkZSB0aGVzZSBDSXMgYXMgYSBndWlkZSB0byB1bmRlcnN0YW5kIGhvdyBsaWtlbHkgdGhlIGVzdGltYXRlIGlzIGZvciB0aGUgdHJ1ZSBwb3B1bGF0aW9uIG1lYW4gQk1JLiBBIHdpZGVyIHJhbmdlIHN1Z2dlc3RzIHRoYXQgdGhlIGVzdGltYXRlIGlzIGxlc3MgYWNjdXJhdGUsIGFzIHRoZXJlIGFyZSBtb3JlIHBvc3NpYmxlIHZhbHVlcyBmb3IgdGhlIHRydWUgbWVhbiB3aXRoIGNyZWRpYmxlIGV2aWRlbmNlLgoKPHU+Tm90ZTo8L3U+IFdoaWxlIFtnZW5kZXJdKGh0dHBzOi8vd3d3LmdlbmRlcnNwZWN0cnVtLm9yZy9xdWljay1saW5rcy91bmRlcnN0YW5kaW5nLWdlbmRlci8pIGFuZCBbc2V4XShodHRwczovL3d3dy53aG8uaW50L2dlbm9taWNzL2dlbmRlci9lbi9pbmRleDEuaHRtbCkgYXJlIG5vdCBhY3R1YWxseSBiaW5hcnksIHRoZSBkYXRhIHByZXNlbnRlZCB0aGF0IGlzIHVzZWQgaW4gdGhpcyBhbmFseXNpcyBvbmx5IGNvbnRhaW5zIGRhdGEgZm9yIGdyb3VwcyBvZiBpbmRpdmlkdWFscyBkZXNjcmliZWQgYXMgbWVuIG9yIHdvbWVuLiAKCiMjIERhdGEgSW1wb3J0CgpGaXJzdCBsZXQncyBkb3dubG9hZCB0aGUgZGF0YToKYGBge3J9Cgp1cmwgPC0gImh0dHBzOi8vc3RhdGljLWNvbnRlbnQuc3ByaW5nZXIuY29tL2VzbS9hcnQlM0ExMC4xMDM4JTJGczQxNTg2LTAxOS0xMTcxLXgvTWVkaWFPYmplY3RzLzQxNTg2XzIwMTlfMTE3MV9NT0VTTTFfRVNNLnBkZiIKdXRpbHM6OmRvd25sb2FkLmZpbGUodXJsLCAicGFwZXJfc3VwcGxlbWVudC5wZGYiKQpgYGAKCk5vdyB0aGF0IHdlIGhhdmUgdGhlIG9iZXNpdHkgcGRmLCB3ZSB3aWxsIHJlYWQgaXQgaW4gdG8gUiB1c2luZyB0aGUgYHBkZnRvb2xzYCBwYWNrYWdlOgoKYGBge3J9CnBkZl9vYmVzaXR5PC1wZGZ0b29sczo6cGRmX3RleHQoaGVyZSgicGFwZXJfc3VwcGxlbWVudC5wZGYiKSkKIyBQREYgZXJyb3I6IAojICJFeHBlY3RlZCB0aGUgb3B0aW9uYWwgY29udGVudCBncm91cCBsaXN0LCAKIyBidXQgd2Fzbid0IGFibGUgdG8gZmluZCBpdCwgb3IgaXQgaXNuJ3QgYW4gQXJyYXkiCgojIEVycm9ycyBsaWtlIHRoaXMgY2FuIGJlIGNvbW1vbiB3aXRoIFBERnMKIyBXZSBjYW4gdGFrZSBhIGxvb2sgYXQgdGhlIGRhdGEgdG8gc2VlIGlmIGl0IHN0aWxsIGxvb2tzIGFzIGV4cGVjdGVkCmBgYAoKTGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIGRhdGEtIHRoZSBgc3VtbWFyeSgpYCBmdW5jdGlvbiBoZWxwcyB1cyB0byBsb29rIGF0IHRoZSBzdHJ1Y3R1cmUgb2YgUiBvYmplY3RzLgoKYGBge3J9CnN1bW1hcnkocGRmX29iZXNpdHkpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHdlIGhhdmUgNjMgZWxlbWVudHMgdGhhdCBhcmUgY2hhcmFjdGVyIHN0cmluZ3MuIFlvdSBtYXkgYWxzbyBub3RpY2UgdGhhdCB0aGUgb3JpZ2luYWwgUERGIGhhcyA2MyBwYWdlcy4gTGV0J3MgdGFrZSBhIGxvb2sgYXQgc29tZSBvZiB0aGVzZSBlbGVtZW50cy4KCmBgYHtyfQpwZGZfb2Jlc2l0eVsxXSAjIHRoaXMgbG9va3MgbGlrZSB0aGUgZmlyc3QgcGFnZQpwZGZfb2Jlc2l0eVsyXSAjIHRoaXMgbG9va3MgbGlrZSB0aGUgc2Vjb25kIHBhZ2UKYGBgCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpwZGZfb2Jlc2l0eVs1NV0gCiMgdGhpcyBsb29rcyBsaWtlIGRhdGEgaW4gYSB0aGUgdGFibGUgd2Ugd2FudApgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iMTAwJSIsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkoaGVyZSkKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgicGFnZTU1LnBuZyIpKQoKYGBgCgoKV2UgY2FuIHNlZSB0aGF0IHRoZSBvdXRwdXQgbG9va3MgcHJldHR5IHNpbWlsYXIgdG8gdGhlIHBhZ2VzIG9mIHRoZSBwZGYsIGJ1dCB0aGUgc3BhY2luZyBpcyBhIGJpdCBhd2t3YXJkLiBOb3RlIHRoYXQgdGhlIHdheSB0aGUgZGF0YSBpcyBkaXNwbGF5ZWQgaXMgcGFydGlhbGx5IGluZmx1ZW5jZWQgYnkgdGhlIHdpZHRoIHNldHRpbmcgb2YgdGhlIFJTdHVkaW8gd2luZG93LiAgCgpXZSBhcmUgaW50ZXJlc3RlZCBpbiBhIHN1cHBsZW1lbnRhcnkgVGFibGUgMy4gd2hpY2ggaGFzIG11bHRpcGxlIHBhZ2VzIGFuZCBpbmNsdWRlcyB0aGUgc2FtZSBoZWFkZXIgb24gZWFjaCBwYWdlOyB3ZSBjYW4gdXNlIHRoYXQgdG8gZGV0ZXJtaW5lIHdoYXQgZWxlbWVudHMgb2Ygb3VyIHBkZl9vYmVzaXR5IGNoYXJhY3RlciBzdHJpbmdzIGluY2x1ZGUgb3VyIHRhYmxlLiBXZSB3aWxsIHVzZSB0aGUgYHN0cl9kZXRlY3QoKWAgZnVuY3Rpb24gb2YgdGhlIGBzdHJpbmdyYCBwYWNrYWdlIHRvIHNlYXJjaCBmb3IgdGhlIGVsZW1lbnRzIHRoYXQgY29udGFpbiB0ZXh0IHRoYXQgaXMgY29uc2lzdGVudGx5IGluIHRoZSBoZWFkZXIuIFRoZSBvdXRwdXQgb2Ygb2YgdGhpcyBmdW5jdGlvbiB3aWxsIHNob3cgd2hpY2ggZWxlbWVudHMgb2YgdGhlIG9iamVjdCAoaW4gdGhpcyBjYXNlIHBhZ2VzIG9mIHRoZSBwZGYpIGluY2x1ZGUgdGhpcyBwYXR0ZXJuIGluZGljYXRlZCBhcyBhICJUUlVFIiBvciAiRkFMU0UiLgoKYGBge3J9CnN0cmluZ3I6OnN0cl9kZXRlY3QocGF0dGVybiA9ICJBZ2Utc3RhbmRhcmRpc2VkIG1lYW4gQk1JIiwgc3RyaW5nID0gcGRmX29iZXNpdHkpCiMgIkFnZS1zdGFuZGFyZGlzZWQgbWVhbiBCTUkiIGlzIHBhcnQgb2YgdGhlIGhlYWRlciBpbiB0aGUgdGFibGUgb24gZXZlcnkgcGFnZS4KIyBUaGlzIHNob3dzIHRoZSBwYWdlcyB0aGF0IGNvbnRhaW4gb3VyIHRhYmxlIG9mIGludGVyZXN0IChhcyBUUlVFIHZhbHVlcykuCmBgYAoKTm93IHdlIHdpbGwgZXh0cmFjdCBqdXN0IHRoZSBkYXRhIGZvciB0aGUgdGFibGUgbm93IGFuZCBjYWxsIGl0IHJ1cmFsX3VyYmFuLiBUbyBkbyB0aGlzIHdlIHdpbGwgdXNlIHRoZSBgc3RyX3N1YnNldCgpYCBmdW5jdGlvbiBvZiB0aGUgc3RyaW5nciBwYWNrYWdlLgoKYGBge3J9CnJ1cmFsX3VyYmFuIDwtc3RyaW5ncjo6c3RyX3N1YnNldChwYXR0ZXJuID0iQWdlLXN0YW5kYXJkaXNlZCBtZWFuIEJNSSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nID1wZGZfb2Jlc2l0eSkKCnN0cihydXJhbF91cmJhbikgCiMgVGhlIHN0cigpIGZ1bmN0aW9uIGlzIHNpbWlsYXIgdG8gdGhlIHN1bW1hcnkgZnVuY3Rpb24KIyBUaGVyZSBhcmUgMTAgcGFnZXMgd29ydGggb2YgZWxlbWVudHMgaW4gb3VyIHJ1cmFsX3VyYmFuIG9iamVjdAoKYGBgCgoKTGV0J3MgY2hlY2sgdGhlIGZpcnN0IGFuZCBsYXN0IHBhZ2U6CgpgYGB7ciwgZXZhbD1GQUxTRX0KY2F0KHJ1cmFsX3VyYmFuWzFdKSAKIyBVc2luZyB0aGUgY2F0KCkgZnVuY3Rpb24gd2hpY2ggc3RhbmRzIGZvciBDb25jYXRlbmF0ZSBBbmQgUHJpbnQgCiMgVGhpcyB3aWxsIGFsbG93IGZvciB0aGUgIlxuIiB2YWx1ZXMgdG8gYmUgc2hvd24gYXMgc3BhY2VzCmBgYAoKCmBgYHtyLCBlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImZpcnN0X3BhZ2VfaW5fUi5wbmciKSkKYGBgCgoKYGBge3IsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiZmlyc3RfcGFnZS5wbmciKSkKYGBgCgpUaGlzIGxvb2tzIHRoZSBzYW1lIGFzIHRoZSBiZWdpbm5pbmcuLi4gaG93IGFib3V0IHRoZSBlbmQ/CgpgYGB7ciwgZXZhbCA9RkFMU0V9CmNhdChydXJhbF91cmJhblsxMF0pCmBgYAoKCmBgYHtyLCBlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImxhc3RfcGFnZV9pbl9SLnBuZyIpKQpgYGAKCgpgYGB7ciwgZWNobyA9IEZBTFNFIH0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgibGFzdF9wYWdlLnBuZyIpKQpgYGAKCgpHcmVhdCEgT3VyIHJ1cmFsX3VyYmFuIG9iamVjdCBsb29rcyBsaWtlIGl0IGNvbnRhaW5zIHRoZSBlbnRpcmUgU3VwcGxlbWVudGFyeSAzIHRhYmxlLCBhcyBib3RoIHRoZSBiZWdpbm5pbmcgYW5kIHRoZSBlbmQgaW5jbHVkZSB0aGUgZGF0YSB3ZSBleHBlY3RlZC4KCiMjIERhdGEgV3JhbmdsaW5nCgpBdCB0aGlzIHBvaW50IHdlIGhhdmUgbGFyZ2Ugc3RyaW5ncyBub3cgZm9yIGVhY2ggcGFnZSBvZiB0aGUgdGFibGUsIGJ1dCB0aGlzIGlzIG5vdCB2ZXJ5IGNvbnZlbmllbnQgdG8gd29yayB3aXRoLiBOb3cgd2Ugd2lsbCB3cmFuZ2xlIHRoZSBkYXRhIGludG8gYSBtb3JlIHVzYWJsZSBmb3JtLiBJZGVhbGx5IHdlIHdvdWxkIGxpa2Ugb3VyIGRhdGEgdG8gYmUgaW4gc29tZSBzb3J0IG9mIHRhYnVsYXIgZm9ybS4KCiMjIyBTZXBhcmF0ZSB0aGUgZGF0YSBpbnRvIGxpbmVzCgpGaXJzdCBpdCB3b3VsZCBiZSB1c2VmdWwgdG8gc2VwYXJhdGUgdGhlIGRhdGEgaW50byBsaW5lcyBvciByb3dzIG9mIHRoZSB0YWJsZS4KYGBge3J9CnJ1cmFsX3VyYmFuIDwtcmVhZHI6OnJlYWRfbGluZXMocnVyYWxfdXJiYW4pCnN0cihydXJhbF91cmJhbikgCiMgbm93IHdlIGhhdmUgNDYxIGxpbmVzCnJ1cmFsX3VyYmFuWzZdIAojIHdlIGNhbiBzZWUgdGhhdCBsaW5lIDYgc2hvd3MgdGhlIGRhdGEgZm9yIGZlbWFsZXMgaW4gQWZnaGFuaXN0YW4gIApgYGAKCiMjIyBSZW1vdmluZyBleGNlc3Mgd2hpdGUtc3BhY2UKCldlIGFsc28gaGF2ZSBhIGxvdCBvZiB3aGl0ZS1zcGFjZS4uLiBsZXQncyBnZXQgcmlkIG9mIHRoZSBleGNlc3Mgd2hpdGUgc3BhY2VzIHVzaW5nIGBzdHJfc3F1aXNoKClgIGFsc28gZnJvbSB0aGUgYHN0cmluZ3JgIHBhY2thZ2UuCgpgYGB7cn0KcnVyYWxfdXJiYW48LXN0cmluZ3I6OnN0cl9zcXVpc2gocnVyYWxfdXJiYW4pIApoZWFkKHJ1cmFsX3VyYmFuKQpgYGAKCk5vdyBpdCBpcyBtdWNoIGVhc2llciB0byBzZWUgdGhlIGRhdGEuCgpJZiB3ZSBsb29rIGF0IHRoZSBlbmQgb2YgdGhlIGZpcnN0IHBhZ2Ugb2YgdGhlIHRhYmxlIGFuZCB0aGUgc3RhcnQgb2YgdGhlIHNlY29uZCB3ZSBjYW4gc2VlIHRoYXQgdGhlIGhlYWRlciBpbmZvcm1hdGlvbiBpcyByZXBlYXRlZCwgYXMgd2VsbCBhcyBhIGxpbmUgd2l0aCB0aGUgcGFnZSBudW1iZXIgYW5kIGFuIGVtcHR5IGxpbmUsIGFuZCBhIGxpbmUgdGhhdCBzYXlzICIyIDIiLgpgYGB7cn0KcnVyYWxfdXJiYW5bNDQ6NTZdCmBgYAoKQWx0aG91Z2ggdGhlIGhlYWRlciB3YXMgbmVjZXNzYXJ5IG9uIGFsbCBvZiB0aGUgcGFnZXMgb2YgdGhlIHBkZiB2ZXJzaW9uIG9mIHRoZSB0YWJsZSwgd2Ugb25seSBuZWVkIHRoYXQgaW5mb3JtYXRpb24gb25jZSBpbiBvdXIgZGF0YS4KCiMjIyBSZW1vdmluZyB1bm5lY2Vzc2FyeSByZXBlYXRlZCBoZWFkZXIgaW5mb3JtYXRpb24KClNvLCBsZXQncyByZW1vdmUgYWxsIHRoZSBoZWFkZXIgaW5mb3JtYXRpb24gYW5kIHRoZSBwYWdlIG51bWJlciBsaW5lcyBmcm9tIHRoZSBydXJhbF91cmJhbiBvYmplY3QsIHRoZW4gd2Ugd2lsbCBtYWtlIGEgc2luZ2xlIGxpbmUgaGVhZGVyIGZvciB0aGUgYmVnaW5uaW5nLgpPbmUgd2F5IHRvIGRvIHRoaXMgaXMgdG8gZmluZCBhbGwgbGluZXMgdGhhdCBpbmNsdWRlIGVpdGhlciAid29tZW4iIG9yICJtZW4iIGFuZCBvbmx5IGtlZXAgdGhpcyBkYXRhLgpGaXJzdCBsZXQncyBzZWUgaG93IG1hbnkgbGluZXMgaW5jbHVkZSAid29tZW4iIG9yICJtZW4iLiBXZSBjYW4gZG8gdGhpcyBieSBmaXJzdCBpZGVudGlmeWluZyB0aGUgbGluZXMgdGhhdCBjb250YWluIHRoZXNlIHBhdHRlcm5zIGFuZCB0aGVuIGNoZWNrIHRoZSBsZW5ndGggb2YgdGhlIHJlc3VsdGluZyB2ZWN0b3IgZm9yIHRoZSBsaW5lIG51bWJlcnMgdGhhdCBjb250YWluIHRoZXNlIHBhdHRlcm5zLgoKYGBge3J9CnN0cmluZ3I6OnN0cl93aGljaChzdHJpbmcgPSBydXJhbF91cmJhbiwgcGF0dGVybiA9ICJXb21lbnxNZW4iKQpsZW5ndGgoc3RyaW5ncjo6c3RyX3doaWNoKHN0cmluZyA9IHJ1cmFsX3VyYmFuLCBwYXR0ZXJuID0gIldvbWVufE1lbiIpKQojIEhlcmUgdGhlICJ8IiBpbmRpY2F0ZXMgdGhhdCB3ZSBhcmUgbG9va2luZyBmb3IgZWl0aGVyICAiV29tZW4iIG9yICJNZW4iCmBgYAoKT0ssIHNvIHRoaXMgbG9va3MgY29ycmVjdC4gVGhpcyBpbmNsdWRlcyBtb3N0IGxpbmVzIGJ1dCB0aGVyZSBhcmUgZ2FwcyB3aGVyZSBhcmUgaGVhZGVyIGlzIGxvY2F0ZWQuIEl0IGxvb2tzIGxpa2UgdGhlcmUgYXJlIDQwMCBsaW5lcyBpbiBvdXIgdGFibGUgdGhhdCBhcmVuJ3QgaGVhZGVycy4KCmBgYHtyfQpydXJhbF91cmJhbiA8LSBzdHJfc3Vic2V0KHN0cmluZyA9IHJ1cmFsX3VyYmFuLCBwYXR0ZXJuID0gIldvbWVufE1lbiIpCmBgYAoKV2UgY2FuIGNoZWNrIG91ciBkYXRhIG5vdyB1c2luZyBlaXRoZXIgaGVhZCgpIG9yIGdsaW1wc2UoKS4KYGBge3J9CmRwbHlyOjpnbGltcHNlKHJ1cmFsX3VyYmFuKQpgYGAKCkdyZWF0LCBub3cgb3VyIHJ1cmFsX3VyYmFuIG9iamVjdCA0MDAgbGluZXMgaW5zdGVhZCBvZiA0NjEsIGxpa2UgaXQgZGlkIGJlZm9yZSB3aGVuIGl0IGNvbnRhaW5lZCB0aGUgcmVkdW5kYW50IGhlYWRlciBpbmZvcm1hdGlvbi4KCmBgYHtyfQpoZWFkKHJ1cmFsX3VyYmFuKQpgYGAKClRoZSBgaGVhZCgpYCBmdW5jdGlvbiBzaG93cyB1cyB0aGUgZmlyc3Qgcm93cyBvciBsaW5lcyBvZiB0aGUgZGF0YSwgd2hpbGUgdGhlIGBnbGltcHNlKClgIGZ1bmN0aW9uIHByb3ZpZGVzIHVzIGluZm9ybWF0aW9uIGFib3V0IHRoZSB0b3RhbCBzaXplIG9mIHRoZSBvYmplY3QgYW5kIHNob3dzIHVzIHRoZSBmaXJzdCBsaW5lIG9yIHJvdy4KCkdyZWF0ISBTbyBub3cgb3VyIGRhdGEgbG9va3MgbXVjaCBiZXR0ZXIgYnV0IHdlIG5lZWQgdG8gYWRkIGJhY2sgb3VyIGhlYWRlciBhbmQgd2Ugd291bGQgbGlrZSB0aGlzIHRvIG9ubHkgYmUgYSBzaW5nbGUgbGluZSB0byBtYWtlIGl0IGVhc3kgdG8gdHJhbnNmb3JtIG91ciBkYXRhIGludG8gYSB0YWJsZSBvciB0YWJsZS1saWtlIG9iamVjdC4KCkhlcmUgaXMgd2hhdCBvdXIgaGVhZGVyIHVzZWQgdG8gbG9vayBsaWtlOgoKYGBge3IsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgibGFzdF9wYWdlLnBuZyIpKQpgYGAKCiMjIyBEZWFsaW5nIHdpdGggc3BhY2luZwoKRmlyc3QgbGV0J3MgdHJ5IHNwbGl0dGluZyBvdXIgaGVhZGVyLWxlc3MgZGF0YSBpbnRvIGNvbHVtbnMgYmFzZWQgb24gc3BhY2VzIHVzaW5nIHRoZSBgc3RyX3NwbGl0KClgIGZ1bmN0aW9uLCB3aGVyZSB3ZSBzcGVjaWZ5IHRoYXQgd2UgYXJlIHNwbGl0dGluZyB0aGUgZGF0YSBiYXNlZCBvbiB0aGUgcGF0dGVybiBvZiBhIHNwYWNlICh0aGUgc3BhY2UgaXMgaW5jbHVkZWQgaW4gcXVvdGVzKToKYGBge3J9CihzdHJfc3BsaXQoc3RyaW5nID0gcnVyYWxfdXJiYW4sIHBhdHRlcm4gPSAiICIsIHNpbXBsaWZ5ID0gVFJVRSkpWzE6MTAsXSAKIyBIZXJlIHdlIHdpbGwgdGFrZSBhIGxvb2sgYXQganVzdCB0aGUgZmlyc3QgMTAgbGluZXMgdXNpbmcgdGhlIFsxOjEwLF0KYGBgCgpUaGlzIGFsbW9zdCB3b3JrZWQsIGJ1dCB1bmZvcnR1bmF0ZWx5IGNvdW50cnkgbmFtZXMgdGhhdCBoYXZlIHNwYWNlcyB3aWxsIGJlIGEgcHJvYmxlbS4gV2UgY2FuIHNlZSB0aGF0IEFtZXJpY2FuIFNhbW9hIGhhcyBiZWVuIGRpdmlkZWQgaW50byB0d28gY29sdW1ucyBhbmQgYWxsIHN1YnNlcXVlbnQgY29sdW1ucyBhcmUgc2hpZnRlZC4KCgpTbyBub3cgbGV0J3MgdHJ5IHRvIGV4dHJhY3QgdGhlIGNvdW50cnkgaW5mb3JtYXRpb24sIGJ5IHNlcGFyYXRpbmcgdGhlIGNvdW50cnkgaW5mb3JtYXRpb24gZnJvbSB0aGUgc2V4IGluZm9ybWF0aW9uIHdoZW4gdGhlIHNleCBpcyBmZW1hbGUuIAoKU2V4IGFsd2F5cyBzdGFydHMgd2l0aCBlaXRoZXIgYSBjYXBpdGFsICJXIiBpZiB0aGUgZ2VuZGVyIGlzIGZlbWFsZS4gI1dlIG5lZWQgdG8gdXNlIGEgc3BhY2UgYmVmb3JlIHRoZSAiVyIgb3RoZXJ3aXNlIHdlIHdpbGwgc3BsaXQgc29tZSBvZiB0aGUgY291bnRyeSBuYW1lcyBpZiB0aGUgbmFtZXMgc3RhcnRzIHdpdGggIlciLiAKCkhlcmUgd2Ugd2lsbCBhbHNvIGludHJvZHVjZSB0aGUgY29uY2VwdCBvZiBwaXBpbmcsIHdoaWNoIHVzZXMgdGhlIGAlPiVgLiBUaGlzIGlzIHJlYWxseSB1c2VmdWwgd2hlbiB3ZSBoYXZlIG11bHRpcGxlIHN0ZXBzLCB3aGljaCB3ZSB3aWxsIHNob3cgc29vbi4KClNvIGZpcnN0IHdlIHdpbGwgc2VsZWN0IGp1c3QgdGhlIGRhdGEgZm9yIFdvbWVuIGFuZCB0aGVuIHNwbGl0IHRoaXMgZGF0YSBiYXNlZCBvbiB0aGUgcGF0dGVybiAiIFdvbWVuIiAoTm90ZSB0aGF0IHRoZSBzcGFjZSBpcyBpbmNsdWRlZCAtIHNvIHRoYXQgaXQgaXMgbm90IHdpdGhpbiB0aGUgY291bnRyeSBkYXRhKS4KCmBgYHtyfQoKV29tZW4gPC0gc3RyX3N1YnNldChzdHJpbmcgPSBydXJhbF91cmJhbiwgcGF0dGVybiA9ICJXb21lbiIpIAojIEZpcnN0IGxldCdzIHN1YnNldCB0aGUgZGF0YSB0byBvbmx5IHRoZSBsaW5lcyB0aGF0IGNvbnRhaW4gIldvbWVuIgoKY291bnRyeV9zcGxpdCA8LVdvbWVuICU+JQogIHN0cmluZ3I6OnN0cl9zcGxpdChwYXR0ZXJuPSAiIFdvbWVuIikgJT4lCiAgdW5saXN0KCkgCgoKI3dlIGNhbiBkbyB0aGUgc2FtZSB0aGluZyB3aXRoIHR3byBwaXBlczoKIyBmaXJzdCB3ZSBzZWxlY3QgdGhlICJXb21lbiIgZGF0YSBhbmQgdGhlbiB3ZSBzcGxpdCB0aGUgZGF0YSBieSAiIFdvbWVuIgojIGZpbmFsbHkgd2UgYXNzaWduIHRoZSBvdXRwdXQgb2YgYm90aCBzdGVwcyB0byB0aGUgb2JqZWN0IGNvdW50cnlfc3BsaXQKCmNvdW50cnlfc3BsaXQgPC0gc3RyX3N1YnNldChzdHJpbmcgPSBydXJhbF91cmJhbiwgcGF0dGVybiA9ICJXb21lbiIpICU+JQogIHN0cmluZ3I6OnN0cl9zcGxpdChwYXR0ZXJuPSAiIFdvbWVuIikgJT4lCiAgdW5saXN0KCkKCmhlYWQoY291bnRyeV9zcGxpdCkKYGBgCgpOb3cgd2UgY2FuIHNlZSB0aGF0IENvdW50cnkgaXMgYWx3YXlzIHRoZSBvZGQgcm93cyBhbmQgdGhlIHJlc3Qgb2YgdGhlIGRhdGEgaXMgdGhlIHJlc3Qgb2YgdGhlIHJvd3MuIApXZSBjYW4gc2VsZWN0IHRoZSBvZGQgcm93cyB1c2luZyB0aGUgPGI+IE1vZHVsdXMgKFJlbWFpbmRlciBmcm9tIGRpdmlzaW9uKSBvcGVyYXRvcjwvYj4uIApUaGlzIG9wZXJhdG9yIGxvb2tzIGxpa2UgdGhpcyBgJSVgLiAKQWxsIG9kZCB2YWx1ZXMgc3VjaCBhcyAzLCA3LCBvciAxNSB3aGVuIGRpdmlkZWQgYnkgMiB3b3VsZCBsZWF2ZSBhIHJlbWFpbmRlciBvZiAxLiAKV2Ugd2lsbCBzZWxlY3QganVzdCB0aGVzZSByb3dzIHVzaW5nIHRoZSBgZmlsdGVyKClgIGZ1bmN0aW9uIG9mIGBkcGx5cmAuCgpgYGB7cn0KY291bnRyeSA8LXRpYmJsZShjb3VudHJ5X3NwbGl0KSAlPiUgCiAgZHBseXI6OmZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMiA9PSAxKSAKYGBgCgpXZSBjYW4gdGFrZSBhIGxvb2sgdG8gbWFrZSBzdXJlIHRoYXQgYWxsIHRoZSBjb3VudHJ5IG5hbWVzIGxvb2sgYXMgZXhwZWN0ZWQ6CmBgYHtyLCBldmFsPSBGQUxTRX0KY291bnRyeQpgYGAKCiMjIyMgey5zY3JvbGxhYmxlIH0KYGBge3IsIGVjaG8gPSBGQUxTRX0KY291bnRyeQpgYGAKIyMjIwoKTG9va3MgZ29vZCEKClRoZSBldmVuIHJvd3MgYXJlIHRoZSByb3dzIHdpdGggdGhlIGRhdGEgZm9yIHdvbWVuLgpUaGVzZSByb3cgdmFsdWVzIGhhdmUgYSByZW1haW5kZXIgb2YgMCB3aGVuIGRpdmlkZWQgYnkgMi4KCmBgYHtyfQpXb21lbl9CTUkgPC10aWJibGUoY291bnRyeV9zcGxpdCkgJT4lIAogIGRwbHlyOjpmaWx0ZXIocm93X251bWJlcigpICUlIDIgPT0gMCkKaGVhZChXb21lbl9CTUkpCmBgYAoKR3JlYXQhIE5vdyB3ZSBoYXZlIGEgbGlzdCBvZiB0aGUgY291bnRyaWVzIHRoYXQgY2FuIGJlIHVzZWQgZm9yIGJvdGggdGhlIG1hbGUgYW5kIGZlbWFsZSBkYXRhLiAKCgpJdCdzIGFsd2F5cyBhIGdvb2QgaWRlYSB0byBjaGVjayB0aGF0IHlvdXIgZGF0YSBvYmplY3RzIGFyZSB0aGUgc2l6ZSB5b3UgZXhwZWN0IHdoZW4gd3JhbmdsaW5nLiAKV2UgY2FuIGRvIHNvIHdpdGggdGhlIGBkaW0oKWAgZnVuY3Rpb24sIHdoaWNoIHNob3dzIHVzIHRoZSBkaW1lbnNpb25zIG9mIGRhdGEgb2JqZWN0cy4KCmBgYHtyfQpkaW0oV29tZW5fQk1JKQpgYGAKR3JlYXQhIFRoZXJlIGFyZSAyMDAgcm93cyBsaWtlIHdlIGV4cGVjdGVkLiAKCldlIGRvIGhvd2V2ZXIgbmVlZCB0byBhZGQgIiBXb21lbiIgYmFjayB0byB0aGlzIGRhdGEuCgpUbyBkbyB0aGlzIHdlIHdpbGwgdXNlIHRoZSBgZ2x1ZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGdsdWVgIHBhY2thZ2UuIAoKYGBge3J9CldvbWVuIDwtZ2x1ZTo6Z2x1ZSgiV29tZW57V29tZW5fQk1JJGNvdW50cnlfc3BsaXR9IikKaGVhZChXb21lbikKIyBoZXJlIHdlIHdpbGwgcGFzdGUgIiBXb21lbiIgaW4gZnJvbXQgb2YgdGhlIFdvbWVuX0JNSSBkYXRhCiMgbm90ZSB0aGF0IHRoZXJlIHdpbGwgYmUgYSBzcGFjZSBpbiBiZXR3ZWVuCiMgVGhpcyBpcyBiZWNhdXNlIHRoZSBzcGFjZSBpcyBhbHJlYWR5IGluIGZyb250IG9mIHRoZSBmaXJzdCBCTUkgdmFsdWUKYGBgCgoKTGV0J3MgZ3JhYiB0aGUgbWFsZSBkYXRhOgoKYGBge3J9CiMgcmVtZW1iZXIgb3VyIHJ1cmFsX3VyYmFuIG9iamVjdCBjb250YWlucyBtYWxlIGRhdGEgZm9yIHRoZSBvZGQgcm93cwoKTWVuIDwtdGliYmxlKHJ1cmFsX3VyYmFuKSAlPiUgCiAgZHBseXI6OmZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMiA9PSAxKSAKaGVhZChNZW4kcnVyYWxfdXJiYW4pCgojIEFnYWluIGxldCdzIG1ha2Ugc3VyZSB3ZSBoYXZlIHRoZSBjb3JyZWN0IG51bWJlciBvZiByb3dzIAoKZGltKE1lbikgCmBgYApIb3cgYWJvdXQgb3VyIG51bWJlciBvZiBjb2x1bW5zPyAKCklmIHdlIHRyeSBzcGxpdHRpbmcgb3VyIGRhdGEgYnkgc3BhY2UgYWdhaW4sIHdpbGwgaXQgaGF2ZSB0aGUgZXhwZWN0ZWQgbnVtYmVyIG9mIGNvbHVtbnM/IFdoYXQgYWJvdXQgdGhlIHJvd3MgdGhhdCBjb250YWluIG5hKiB2YWx1ZXM/CmBgYHtyfQojIExldCdzIGp1c3QgdGFrZSB0aGUgTWVuIGRhdGEgdGhhdCBjb250YWlucyBuYSogdmFsdWVzCiMgVGhpcyBjb2x1bW4gaXMgY2FsbGVkIHJ1cmFsX3VyYmFuCnVua25vd24gPC1NZW4gJT4lZmlsdGVyKHN0cl9kZXRlY3QocGF0dGVybiA9Im5hXFwqIiwgc3RyaW5nID0gcnVyYWxfdXJiYW4pKSAKCiMgTm93IHdlIGNhbiB0cnkgc3BsaXR0aW5nIGJ5IGEgc3BhY2UKdGliYmxlOjphc190aWJibGUoc3RyX3NwbGl0KHVua25vd24kcnVyYWxfdXJiYW4sICIgIiwgc2ltcGxpZnkgPSBUUlVFKSkKCmBgYAoKIyMjIERlYWxpbmcgd2l0aCBOQSB2YWx1ZXMKClNvIGNsb3NlISBOb3RpY2UgdGhhdCB0aGUgIm5hKiIgdmFsdWVzICBoYXZlIHNoaWZ0ZWQgdGhlIHN1YnNlcXVlbnQgdmFsdWVzIHdpdGhpbiB0aGUgY29sdW1ucyBiZWNhdXNlIHR5cGljYWxseSB0aGVyZSBpcyBhIHNwYWNlIGJldHdlZW4gdGhlIEJNSSBhbmQgdGhlIGNyZWRpYmxlIGludGVydmFscy4gSGVyZSB3ZSBjYW4gc2VlIHRoaXMgZGF0YSBpbiBvdXIgb3JpZ2luYWwgcGRmOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSIxMDAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgibWlzc2luZ19wZGYucG5nIikpCmBgYAoKV2UgbmVlZCB0byByZXBsYWNlIG91ciBuYSogdmFsdWVzICB3aXRoIHNvbWV0aGluZyB0aGF0IGluY2x1ZGVzIGEgc3BhY2Ugc28gdGhhdCB3aGVuIHdlIHNlcGFyYXRlIG91ciBkYXRhIGJ5IHNwYWNlIHdlIHdpbGwgaGF2ZSB0d28gdmFsdWVzIGluc3RlYWQgb2Ygb25lIHdoZW4gd2UgaGF2ZSBhbiBuYSogLiBUaGVyZWZvcmUsIG5hKiBuYSogc2hvdWxkIHdvcmsuCgpgYGB7cn0KY2xhc3MoTWVuJHJ1cmFsX3VyYmFuKQojIEluIG9yZGVyIHRvIHVzZSB0aGUgZnVuY3Rpb25zIHdpdGhpbiB0aGUgc3RyaW5nciBwYWNrYWdlLCAKIyBvdXIgTWVuIGRhdGEgbmVlZHMgdG8gYmUgb2YgY2hhcmFjdGVyIGNsYXNzCk1lbjwtYXMuY2hhcmFjdGVyKE1lbiRydXJhbF91cmJhbikgCiMgVGhpcyBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gY2hhbmdlIHRoZSBmYWN0b3IgZGF0YSAKIyB3aXRoaW4gTWVuJHJ1cmFsX3VyYmFuIHRvIHRoZSBjaGFyYWN0ZXIgY2xhc3MKIyBXZSBhcmUgYWxzbyBjaGFuZ2luZyB0aGUgc3RydWN0dXJlIHNvIHRoYXQgdGhlIGRhdGEgCiMgaXMgbm90IHdpdGhpbiBhIHZlY3RvciBjYWxsZWQgcnVyYWxfdXJiYW4KTWVuPC1zdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwoc3RyaW5nID0gTWVuLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJuYVxcKiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICJuYVxcKiBuYVxcKiIpIAojIFRoZSBcXCBhcmUgbmVjZXNzYXJ5IGJlY2F1c2UgdGhlICogaXMgYSBzcGVjaWFsIGNoYXJhY3RlciAKIyBUaGUgKiB3b3VsZCB0eXBpY2FsbHkgaW5kaWNhdGUgYW55IHBvc3NpYmxlIHZhbHVlLCAKIyBidXQgaGVyZSB3ZSBhY3R1YWxseSB3YW50IGEgIioiIGluc3RlYWQKIyBUaHVzIHRoZSBkb3VibGUgYmFja3NsYXNoIGRvZXMgdGhhdCBmb3IgdXMKIyBIZXJlIHdlIGFyZSByZXBsYWNpbmcgYWxsIG9jY3VyZW5jZXMgb2YgdGhlIG5hKiB2YWx1ZXMgCiModGh1cyBzdHJfcmVwbGFjZV9hbGwgaW5zdGVhZCBvZiBzdHJfcmVwbGFjZSkgd2l0aCBuYSogbmEqLiAKYGBgCgpMZXQncyBjaGVjayB0aGF0IGl0IHdvcmtlZC4uLgpgYGB7cn0KTWVuWzIwOjMwXQpgYGAKCkdyZWF0IQoKTm93IGZvciB0aGUgV29tZW4gZGF0YSBvYmplY3QKYGBge3J9CmNsYXNzKFdvbWVuKQojIHRoZSBmZW1hbGUgZGF0YSBpcyBhbHJlYWR5IGNoYXJhY3RlciB0eXBlCldvbWVuPC1zdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwoc3RyaW5nID0gV29tZW4sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAibmFcXCoiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICJuYVxcKiBuYVxcKiIpIApXb21lblsyMDozMF0KYGBgCgoKR3JlYXQsIG5vdyB3ZSBjYW4gc3BsaXQgb3VyIGRhdGEgYnkgc3BhY2VzLgoKIyMjIFNwbGl0dGluZyB0aGUgZGF0YQoKCmBgYHtyfQpNZW4gPC10aWJibGU6OmFzX3RpYmJsZShzdHJfc3BsaXQoTWVuLCAiICIsIHNpbXBsaWZ5ID0gVFJVRSkpCiMgTm90ZSBoZXJlIHdlIG5lZWQgdG8gdXNlIHRoZSBjb2x1bW4gb2YgV29tZW4gdGhhdCBoYXMgdGhlIGRhdGEKaGVhZChNZW4pCldvbWVuPC1hc190aWJibGUoc3RyX3NwbGl0KFdvbWVuLCAiICIsIHNpbXBsaWZ5ID0gVFJVRSkpCiMgTm90ZSBoZXJlIHdlIG5lZWQgdG8gdXNlIHRoZSBjb2x1bW4gb2YgV29tZW4gdGhhdCBoYXMgdGhlIGRhdGEKaGVhZChXb21lbikKV29tZW5bMjA6MzAsXSAKIyBXZSBjYW4gc2VlIHRoYXQgb3VyIG5hIHZhbHVlcyBsb29rIGNvcnJlY3QKYGBgCiBMb29rcyBnb29kIQogCiAKIyMjIEFkZGluZyBuZXcgaGVhZGVyCgpXZSBjYW4gc2VlIGZyb20gb3VyIHBkZiBhbmQgb3VyIG9iamVjdCBjYWxsZWQgaGVhZGVyIHdoYXQgdGhlIGhlYWRlciB3YXMgbGlrZS4gTGV0J3MgYWxzbyBtYWtlIGEgbmV3IHNpbmdsZSBsaW5lIGhlYWRlciwgYnV0IGxldCdzIHdhaXQgdG8gYWRkIENvdW50cnk6CgpgYGB7cn0KI2hlYWRlcgpuZXdfaGVhZGVyIDwtYygiU2V4IiwiTmF0aW9uYWxfQk1JXzE5ODUiLCAiTmF0aW9uYWxfQk1JXzE5ODVfQ0kiLCAiUnVyYWxfQk1JXzE5ODUiLCAKICAgICAgICAgICAgICAgIlJ1cmFsX0JNSV8xOTg1X0NJIiwgIlVyYmFuX0JNSV8xOTg1IiwgIlVyYmFuX0JNSV8xOTg1X0NJIiwgIk5hdGlvbmFsX0JNSV8yMDE3IiwKICAgICAgICAgICAgICAgIk5hdGlvbmFsX0JNSV8yMDE3X0NJIiwiUnVyYWxfQk1JXzIwMTciLCAiUnVyYWxfQk1JXzIwMTdfQ0kiLCAiVXJiYW5fQk1JXzIwMTciLCAKICAgICAgICAgICAgICAgIlVyYmFuX0JNSV8yMDE3X0NJIikKYGBgCgoKTGV0J3MgY2hhbmdlIHRoZSBuYW1lcyBvZiBvdXIgY29sdW1ucyBvZiBvdXIgdGliYmxlcyB0byB0aGlzIG5ldyBoZWFkZXIgZm9yIG91ciBNZW4gYW5kIFdvbWVuIGRhdGEKCmBgYHtyfQpuYW1lcyhXb21lbik8LW5ld19oZWFkZXIKbmFtZXMoTWVuKTwtbmV3X2hlYWRlcgpgYGAKCgpOb3cgd2Ugd2lsbCBhZGQgb3VyIGNvdW50cnkgZGF0YSB0byBib3RoIG91ciBNZW4gYW5kIFdvbWVuIHRpYmJsZXMgdXNpbmcgdGhlIGBiaW5kX2NvbHMoKWAgZnVuY3Rpb246CgpgYGB7cn0KV29tZW4gPC0gZHBseXI6OmJpbmRfY29scyhjb3VudHJ5LCBXb21lbikKIyBUaGlzIHdpbGwgYWRkIHRoZSBjb3VudHJ5IGFzIGEgbmV3IGNvbHVtbiB0byB0aGUgV29tZW4gZGF0YSBvYmplY3Qgb24gdGhlIGxlZnQgCk1lbiA8LSBkcGx5cjo6YmluZF9jb2xzKGNvdW50cnksIE1lbikgCiMgVGhpcyB3aWxsIGFkZCB0aGUgY291bnRyeSBhcyBhIG5ldyBjb2x1bW4gdG8gdGhlIE1lbiBkYXRhIG9iamVjdCBvbiB0aGUgbGVmdCAKaGVhZChXb21lbikKYGBgCgojIyMgQ2hhbmdpbmcgdmFyaWFibGUgbmFtZXMKSGVyZSB3ZSB3aWxsIGNoYW5nZSB0aGUgdmFyaWFibGUgbmFtZSBvZiB0aGUgY291bnRyeSBkYXRhIHRvIGNvdW50cnksIGN1cnJlbnRseSBpdCBpcyBjYWxsZWQgY291bnRyeV9zcGxpdC4gSGVyZSB3ZSB3aWxsIGFsc28gaW50cm9kdWNlIHRoZSBjb25jZXB0IG9mIHRoZSBhc3NpZ25tZW50IHBpcGUuIEluIHRoaXMgY2FzZSBvdXIgcGlwZSBvcGVyYXRvciBsb29rcyBsaWtlIHRoaXMgYCU8PiVgIC4gIFVzaW5nIHRoaXMgZmFuY2llciBwaXBlIHJlcXVpcmVzIGFub3RoZXIgcGFja2FnZSwgIGNhbGxlZCBgbWFncml0dHJgLiBUaGUgb3RoZXIgc2ltcGxlciBwaXBlIG9wdGlvbnMgZnJvbSB0aGlzIHBhY2thZ2UgYXJlIGxvYWRlZCB3aXRoIGB0aWR5dmVyc2VgIChpZiB5b3UgdXNlZCBgbGlicmFyeSh0aWR5dmVyc2UpYCB3aGljaCBsb2FkcyBtb3N0IHRpZHl2ZXJzZSBwYWNrYWdlcyksIGJ1dCBub3QgdGhpcyBmYW5jaWVyIHZlcnNpb24uIAoKVGhlIGA+YCBwb3J0aW9uIG9mIHRoZSBwaXBlIHN0aWxsIGJlaGF2ZXMgbGlrZSBhIG5vcm1hbCBwaXBlLCB3aGlsZSB0aGUgYDxgIHBvcnRpb24gb2YgdGhlIHBpcGUgbWFrZXMgYW4gYXNzaWdubWVudCB0byB3aGF0ZXZlciB0aGUgYDxgaXMgcG9pbnRpbmcgdG8sIGp1c3QgbGlrZSB3aGVuIHdlIHVzZSB0aGUgdHlwaWNhbCBhc3NpZ25tZW50IG9wZXJhdG9yIGA8LWAuIAoKYGBge3J9CiMgbGlicmFyeShtYWdyaXR0cikgCiMgV2UgY2FuJ3QgdXNlIHRoZSBgJTw+JWAgdW5sZXNzIHdlIGxvYWQgdGhlIG1hZ3JpdHRyIHBhY2thZ2UKIyBXZSBoYXZlIGFscmVhZHkgZG9uZSB0aGlzIGJ1dCB3ZSBpbmNsdWRlIHRoaXMgZm9yIGlsbHVzdHJhdGl2ZSBwdXJwb3Nlcy4KIyBIZXJlIHdlIHdpbGwganVzdCB1c2UgdGhlIHRyYWRpdGlvbmFsIGFzc2lnbm1lbnQgc3RyYXRlZ3kKCldvbWVuPC1kcGx5cjo6cmVuYW1lKFdvbWVuLCBDb3VudHJ5ID0gY291bnRyeV9zcGxpdCkgCiMgV2UgaGF2ZSByZW5hbWVkIHRoZSBjb3VudHJ5X3NwbGl0IHZhcmlhYmxlIHRvIGJlIGNhbGxlZCBDb3VudHJ5CgojIEhlcmUgd2UgcmVhc3NpZ24gTWVuIHVzaW5nIHRoZSBwaXBlIHN0cmF0ZWd5Ck1lbiAlPD4lcmVuYW1lKENvdW50cnkgPSBjb3VudHJ5X3NwbGl0KSAKIyBXZSBoYXZlIHJlbmFtZWQgdGhlIGNvdW50cnlfc3BsaXQgdmFyaWFibGUgdG8gdG8gYmUgY2FsbGVkIGNvdW50cnkKIyBXZSBoYXZlIGFsc28gcmVhc3NpZ25lZCBNZW4gdG8gdGhlIGRhdGEgb2JqZWN0IAojIHdoaWNoIGhhcyB0aGUgY291bnRyeSB2YXJpYWJsZSByZW5hbWVkCmBgYAoKCiMjIyBKb2luaW5nIHRoZSBkYXRhCgpOb3cgd2UgY2FuIGNvbWJpbmUgb3VyIE1lbiBhbmQgV29tZW4gZGF0YSB1c2luZyB0aGUgYGZ1bGxfam9pbigpYCBmdW5jdGlvbiBvZiBgZHBseXJgLiAKVGhpcyB3aWxsIHB1dCBhbGwgdGhlIG1hbGUgZGF0YSBmaXJzdCAoeCkgYW5kIGFsbCB0aGUgZmVtYWxlIGRhdGEgc2Vjb25kICh5KS4KCmBgYHtyfQpCTUk8LWRwbHlyOjpmdWxsX2pvaW4oeCA9IE1lbiwgeSA9IFdvbWVuKQojIExldCdzIGNoZWNrIHRoZSBzaXplIG9mIG91ciBCTUkgZGF0YS4uLiBpdCBzaG91bGQgaGF2ZSA0MDAgcm93cyAob2JzKS4Kc3RyKEJNSSkKYGBgCgoKIyMjIFNvcnRpbmcgdGhlIGRhdGEKCk5vdyBMZXRzIHNvcnQgdGhlIGRhdGEgYnkgY291bnRyeToKCmBgYHtyfQpCTUkgPC1kcGx5cjo6YXJyYW5nZShCTUksIENvdW50cnkpCmhlYWQoQk1JKQoKYGBgCgpPdXIgZGF0YSBpcyBsb29raW5nIGdyZWF0ISAKTm93IHdlIG1pZ2h0IHdhbnQgdG8gbWFrZSBzdXJlIHRoYXQgb3VyIG9ic2VydmF0aW9ucyBmb3IgZWFjaCB2YXJpYWJsZSBsb29rIHRoZSB3YXkgd2Ugd2FudC4gCkluIG90aGVyIHdvcmRzLCBpZiB3ZSB3YW50IHRvIG1ha2UgcGxvdHMgYWJvdXQgTmF0aW9uYWwgQk1JIGluIDE5ODUgdGhlbiB3ZSB3b3VsZCBuZWVkIG91ciB2YWx1ZXMgdG8gYmUgbnVtZXJpYy4gTG9va2luZyBhdCBvdXIgQk1JIGRhdGEgdXNpbmcgYHN0cigpYCwgd2UgY2FuIHNlZSB0aGUgdHlwZSBvZiBkYXRhIGZvciBlYWNoIG9mIG91ciB2YXJpYWJsZXMgbGlzdGVkIGp1c3QgYWZ0ZXIgdmFyaWFibGUgbmFtZSBhbmQgdGhlICI6IiBjb2xvbi4gTG9va3MgbGlrZSBub25lIG9mIG91ciBCTUkgZGF0YSBpcyBhY3R1YWxseSBudW1lcmljLCBidXQgb2YgdGhlIGNsYXNzIGNoYXJhY3Rlci4gTGV0J3MgY2hhbmdlIHRoYXQgbm93LgoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIGV2YWx9CnN0cihCTUkpCmBgYAoKV2UgY291bGQgY2hhbmdlIHRoZXNlIHZhbHVlcyB0byBiZSBudW1lcmljIHdpdGggNiBsaW5lcyBvZiBjb2RlIGxpa2UgdGhpczoKCmBgYHtyLCBldmFsID0gVFJVRX0KQk1JJE5hdGlvbmFsX0JNSV8xOTg1JTw+JSBhcy5udW1lcmljCkJNSSRSdXJhbF9CTUlfMTk4NSU8PiUgYXMubnVtZXJpYwpCTUkkVXJiYW5fQk1JXzE5ODUlPD4lIGFzLm51bWVyaWMKCkJNSSROYXRpb25hbF9CTUlfMjAxNyU8PiUgYXMubnVtZXJpYwpCTUkkUnVyYWxfQk1JXzIwMTclPD4lIGFzLm51bWVyaWMKQk1JJFVyYmFuX0JNSV8yMDE3JTw+JSBhcy5udW1lcmljCgojICBBbmQgaWYgd2UgZGlkIHRoaXMgd2Ugd291bGQgc2VlIHRoZXNlIHZhcmlhYmxlcyAKIyAgc2hvdyBhcyAibnVtIiB3aGljaCBzdGFuZHMgZm9yIG51bWVyaWMKc3RyKEJNSSkKYGBgCgpPciB3ZSBjYW4gdXNlIGEgbW9yZSBhdXRvbWF0ZWQgd2F5IHdpdGggdGhlIGBtYXAoKWAgZnVuY3Rpb24gb2YgdGhlIGBwdXJycmAgcGFja2FnZToKYGBge3J9CkJNSV9udW1lcmljIDwtIGFzX3RpYmJsZShwdXJycjo6bWFwKAogIChCTUkgJT4lIHNlbGVjdCgtbWF0Y2hlcygiQ0l8U2V4fENvdW50cnkiKSkpLCBhcy5udW1lcmljKSkgCiMgVGhlIG1hcCBmdW5jdGlvbiBvZiB0aGUgcHVycnIgcGFja2FnZSBhbGxvd3MgdXMgdG8gYXBwbHkgdGhlIAojIGFzLm51bWVyaWMoKSBmdW5jdGlvbiB0byBhbGwgdGhlIHNlbGVjdGVkIGNvbHVtbnMgb2YgQk1JIAojIFdlIGhhdmUgc2VsZWN0ZWQgdGhvc2UgdGhhdCBkb250IGNvbnRhaW4gQ0ksIFNleCwgb3IgQ291bnRyeSBpbiB0aGUgY29sdW1uIG5hbWUgCiMgSWYgeW91IGFyZSBmYW1pbGlhciB3aXRoIGFwcGx5KCksIHRoaXMgZnVuY3Rpb24gaXMgdmVyeSBzaW1pbGFyCkJNSV9udW1lcmljICU8PiUgbXV0YXRlKENvdW50cnkgPUJNSSRDb3VudHJ5LCBTZXggPUJNSSRTZXgpCmhlYWQoQk1JX251bWVyaWMpCiMgSW4gdGhpcyBjYXNlIG91ciBudW1lcmljIGRhdGEgaXMgY2xhc3MgZGJsCiMgVGhpcyBtZWFucyBkb3VibGUtcHJlY2lzaW9uIGZsb2F0aW5nIHBvaW50IG51bWJlcnMgKHdpdGggZGVjaW1hbHMpCiMgVGhlIGFsdGVybmF0aXZlIG51bWVyaWMgb3B0aW9uIGlzIHRoZSBpbnRlZ2FyIGNsYXNzCmBgYAoKCkl0IGlzIGdlbmVyYWxseSB1c2VmdWwgdG8gZ2V0IHRoZSBkYXRhIGluIHdoYXQgaXMgY2FsbGVkIDxiPmxvbmc8L2I+IGZvcm1hdCBmb3Igb3RoZXIgYW5hbHlzZXMsIGFuZCBwYXJ0aWN1bGFybHkgZm9yIHBsb3R0aW5nLiAKCkZvciBhIG1vcmUgZGV0YWlsZWQgZGVzY3JpcHRpb24gYWJvdXQgdGhpcywgcGxlYXNlIHNlZSB0aGlzIFtjYXNlIHN0dWR5XShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8vb2NzLWhlYWx0aGV4cGVuZGl0dXJlL29jcy1oZWFsdGhleHBlbmRpdHVyZS5odG1sKQoKQmFzaWNhbGx5IHdoYXQgdGhlIGxvbmcgZm9ybWF0IHdpbGwgaGF2ZSBtb3JlIHJvd3MgYW5kIGZld2VyIGNvbHVtbnMuClRodXMgd2UgY2FuIGNvbWJpbmUgb3IgImdhdGhlciIgc29tZSBjb2x1bW5zIHRvZ2V0aGVyLgpJbiBvdXIgY2FzZSB3ZSBjYW4gcHV0IGFsbCB0aGUgZGlmZmVyZW50IEJNSSBkYXRhIHRvZ2V0aGVyIGluIG9uZSBsb25nIGNvbHVtbi4KV2Ugd2lsbCBjcmVhdGUgYSBuZXcgY29sdW1uIHRoYXQgdGVsbHMgdXMgd2hhdCBlYWNoIHJvdyBvZiB0aGUgbmV3IEJNSSBjb2x1bW4gcmVwcmVzZW50cy4KSW4gb3RoZXIgd29yZHMsIGl0IHdpbGwgdGVsbCB1cyB3aGF0IHRoZSBvcmlnaW5hbCBjb2x1bW4gd2FzLgoKVG8gZG8gdGhpcyB3ZSB3aWxsIHVzZSB0aGUgYGdhdGhlcigpYCBmdW5jdGlvbiBvZiB0aGUgYHRpZHlyYCBwYWNrYWdlOgoKYGBge3J9CkJNSV9sb25nIDwtdGlkeXI6OmdhdGhlcihkYXRhID1CTUlfbnVtZXJpYywga2V5ID0gY2xhc3NfQk1JLCB2YWx1ZSA9IEJNSSwgTmF0aW9uYWxfQk1JXzE5ODU6VXJiYW5fQk1JXzIwMTcsIGZhY3Rvcl9rZXkgPSBGQUxTRSkgCiMgVGhlIGRhdGEgdmFsdWUgaW5kaWNhdGVzIHdoYXQgZGF0YSB5b3Ugc3RhcnQgd2l0aAojIFRoZSBrZXkgaW5kaWNhdGVzIHRoZSBuZXcgbmFtZSBvZiB0aGUgY29sdW1uIHRoYXQgd2lsbCBub3cgY29udGFpbiAKIyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgdmFsdWVzIG9mIHRoZSBjb2x1bW5zIHdlIHdpbGwgcHV0IHRvZ2V0aGVyCiMgVGhlIHZhbHVlIGlzIHRoZSBuYW1lIG9mIHRoZSBjb2x1bW4gZm9yIHRoZSB2YWx1ZXMgZm9yIAojIGFsbCB0aGUgY29sdW1ucyB0aGF0IGFyZSBiZWluZyBwdXQgdG9nZXRoZXIKIyBUaGUgIjoiIGNhbiBiZSB1c2VkIHRvIGluZGVudGlmeSB0aGUgc3RhcnQgYW5kIGVuZCBvZiB0aGUgY29sdW1uIG5hbWVzCiMgdGhhdCB5b3UgYXJlIHB1dHRpbmcgdG9nZXRoZXIKIyBUaGUgZmFjdG9yX2tleSBwYXJhbWF0ZXIgZGV0ZXJtaW5lcyBpZiB0aGUgbmV3bHkgY3JlYXRlZCBrZXkgY29sdW1uIAojIHNob3VsZCBiZSBldmFsdWF0ZWQgYXMgYSBmYWN0b3Igb3Igbm90CmhlYWQoQk1JX2xvbmcpCmBgYAoKSXQgd291bGQgYmUgdXNlZnVsIHRvIHBhcnNlIHRoZSAxOTg1IGFuZCB0aGUgMjAxNyBkYXRhLiBXZSBjYW4gZG8gc28gYnkgc2VwYXJhdGluZyB0aGUgcGFydHMgb2YgdGhlIGNsYXNzX0JNSSBjb2x1bW4gdXNpbmcgdGhlIGBzZXBhcmF0ZSgpYCBmdW5jdGlvbiBvZiB0aGUgYHRpZHlyYCBwYWNrYWdlLiAKSW4gb3VyIGNhc2Ugd2Ugd2lsbCByZXBsYWNlIHRoZSBjbGFzc19CTUkgY29sdW1uIHdpdGggdHdvIG5ldyBjb2x1bW5zLgoKYGBge3J9CkJNSV9sb25nJTw+JSB0aWR5cjo6c2VwYXJhdGUoY2xhc3NfQk1JLCBjKCJSZWdpb24iLCBOQSwgIlllYXIiKSkgCiMgV2Ugd2lsbCBzZXBhcmF0ZSB0aGUgY2xhc3NfQk1JIGNvbHVtbiBvZiB0aGUgQk1JX2xvbmcgdGliYmxlCiMgVGhpcyBpcyBiYXNlZCBvbiB0aGUgdW5kZXJzY29yZXMgYW5kIGNyZWF0ZSB0d28gbmV3IGNvbHVtbnMKIyBUaGUgZmlyc3QgY29sdW1uIHdpbGwgYmUgY2FsbGVkIFJlZ2lvbgojIEl0IHdpbGwgY29udGFpbiB0aGUgMXN0IHBhcnQgb2YgdGhlIGNsYXNzX0JNSSBkYXRhIGJlZm9yZSB0aGUgMXN0IHVuZGVyc2NvcmUKIyBUaGUgMm5kIGNvbHVtbiB3aWxsIGJlIGNhbGxlZCBZZWFyCiMgSXQgd2lsbCBjb250YWluIHRoZSAzcmQgcGFydCBvZiB0aGUgZGF0YSBiYXNlZCBvbiB1bmRlcnNjb3JlcwojIFRoZSBtaWRkbGUgcGFydCBvZiB0aGUgY29sdW1uIHdpbGwgbm90IGJlIHVzZWQgdG8gY3JlYXRlIGFueSBuZXcgY29sdW1ucwpoZWFkKEJNSV9sb25nKQoKIyBMZXQncyBzZWUgaG93IHRoZSBkaW1lbnNpb25zIG9mIHRoZSBCTUkgZGF0YSBoYXZlIGNoYW5nZWQgaW4gbG9uZyBmb3JtYXQ6CgpkaW0oQk1JX251bWVyaWMpCmRpbShCTUlfbG9uZykKCgpgYGAKCiMjIyMgey5xdWVzdGlvbl9ibG9ja30KPHU+UXVlc3Rpb24gb3Bwb3J0dW5pdHk6PC91PiBXaHkgZXhhY3RseSBhcmUgdGhlcmUgMiw0MDAgcm93cyBub3c/CgojIyMjCgoKR3JlYXQhIG91ciBkYXRhIGlzIHZlcnkgdXNhYmxlIG5vdyBpbiB0aGlzIGZvcm1hdCEKCgpgYGB7ciwgZWNobyA9IEZBTFNFfQpzYXZlKEJNSV9udW1lcmljLCBCTUlfbG9uZywgZmlsZSA9IGhlcmUoIldyYW5nbGVkX2RhdGEucmRhIikpCgpgYGAKIyMgRGF0YSBFeHBsb3JhdGlvbgoKTm93IHRoYXQgb3VyIGRhdGEgaXMgY2xlYW4gYW5kIGluIGEgZm9ybWF0IHRoYXQgd2UgY2FuIHdvcmsgd2l0aCwgd2UgY2FuIHN0YXJ0IHRvIHRha2UgYSBsb29rIGF0IHRoZSBkYXRhIGFuZCBob3cgZGlmZmVyZW50IGdyb3VwcyBtaWdodCBjb21wYXJlLgoKU3RhdGlzdGljYWxseSBzcGVha2luZyB0aGVyZSBhcmUgdGVzdHMgdGhhdCBjYW4gYWxsb3cgdXMgdG8gZXZhbHVhdGUgaWYgdGhlIG1lYW5zIG9mIHRoZSBncm91cHMgYXJlIGRpZmZlcmVudC4gRmlyc3QgbGV0J3Mgc2VlIGhvdyBvdXIgZGF0YSBsb29rcyBpbiBnZW5lcmFsLgoKIyMjIEdlbmVyYWwgc3VtbWFyeQpTdGFydCBoZXJlIGlmIG5vdCB3b3JraW5nIHRocm91Z2ggZGF0YSBpbXBvcnQgYW5kIHdyYW5nbGluZwoKYGBge3IsIGVjaG8gPSBGQUxTRX0KbG9hZChoZXJlKCJXcmFuZ2xlZF9kYXRhLnJkYSIpKQoKYGBgCgpgYGB7cn0Kc3VtbWFyeShCTUlfbnVtZXJpYykKIyBXZSBjYW4gc2VlIHRoYXQgdGhlIG1lYW4gIEJNSSBlc3RpbWF0ZXMgYXJlIGxhcmdlciBpbiAyMDE3CiMgSXMgdGhpcyBhIG1lYW5pbmdmdWwgaW5jcmVhc2U/CmBgYApPSywgc28gb3VyIG1lYW5zIGFyZSBmYWlybHkgc2ltaWxhciwgYnV0IHdlIGNhbiBzZWUgc29tZSBkaWZmZXJlbmNlcy4gClRoZSBxdWVzdGlvbiBpcyBpZiB0aG9zZSBkaWZmZXJlbmNlcyBhcmUgbWVhbmluZ2Z1bC4gClRoaXMgaXMgZGlmZmljdWx0IHRvIGRldGVybWluZSB3aXRob3V0IGEgc3RhdGlzdGljYWwgdGVzdC4KCkxldHMgbG9vayBhdCB0aGUgZGF0YSBzZXBhcmF0ZWx5IGJ5IGdlbmRlcjoKCmBgYHtyfQojV29tZW46CkJNSV9udW1lcmljICU+JSAKICBzdWJzZXQoU2V4ID09ICJXb21lbiIpICU+JSAKICBzdW1tYXJ5KCkKCmBgYAoKYGBge3J9CiNNZW4KQk1JX251bWVyaWMgJT4lIAogIHN1YnNldChTZXggPT0gIk1lbiIpICU+JSAKICBzdW1tYXJ5KCkKYGBgCgpJdCBsb29rcyBsaWtlIG1lYW4gQk1JcyBoYXZlIGluY3JlYXNlZCBpbiBhbGwgcmVnaW9ucyBmb3IgYm90aCBtZW4gYW5kIHdvbWVuLiBJdCBpcyB1bmNsZWFyIHRob3VnaCBpZiB0aGlzIGNoYW5nZSBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LgoKCiMjIyBEaXN0cmlidXRpb25zCgpJbiBvcmRlciB0byBhcHBseSBhIHN0YXRpc3RpY2FsIHRlc3QgdG8gY29tcGFyZSB0aGUgbWVhbnMsIG9uZSBvZiB0aGUgZmlyc3QgdGhpbmdzICB0byBkbyBpcyB0byBwbG90IHRoZSBmcmVxdWVuY3kgb2YgdGhlIGRpZmZlcmVudCBwb3NzaWJsZSB2YWx1ZXMuIFRoaXMgaXMgY2FsbGVkIGEgPGI+ZGlzdHJpYnV0aW9uPC9iPi4gVG8gZG8gdGhpcyB3ZSBjYW4gdXNlIHRoZSBgaGlzdCgpYCBmdW5jdGlvbiB0byBjcmVhdGUgYSBoaXN0b2dyYW0uCgpJZiB0aGUgZGF0YSB3ZXJlIHdoYXQgd2UgY2FsbCA8Yj5ub3JtYWxseSBkaXN0cmlidXRlZDwvYj4gIG9yICBmb2xsb3dlZCBhIDxiPiBHYXVzc2lhbiBkaXN0cmlidXRpb24gPC9iPiB0aGVuIHRoZSBkaXN0cmlidXRpb24gc2hvdWxkIGJlIGVxdWFsbHkgY2VudGVyZWQgYXJvdW5kIHRoZSBtZWFuIGFuZCB3b3VsZCBsb29rIHNvbWV0aGluZyBsaWtlIHRoaXM6CgpgYGB7cn0Kbm9ybV9CTUlfZXhfZGF0YSA8LSB0aWJibGUobm9ybV9kYXRhID1ybm9ybShuID0gMjAwLCBtZWFuID0gMjQpKQojIFRoZSBybm9ybSgpIGZ1bmN0aW9uIGFsbG93cyB1cyB0byBtYWtlIGEgdmVjdG9yIG9mIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIGRhdGEKIyBjZW50ZXJlZCBhcm91bmQgdGhlIG1lYW4gb2YgMjQKaGVhZChub3JtX0JNSV9leF9kYXRhKQpoaXN0KG5vcm1fQk1JX2V4X2RhdGEkbm9ybV9kYXRhKQpgYGAKCkFsdGVybmF0aXZlbHkgd2UgY2FuIHBsb3QgdGhpcyB1c2luZyB0aGUgYGdlb21faGlzdCgpYCBmdW5jdGlvbiBvZiB0aGUgYGdncGxvdDJgIHBhY2thZ2UuIFRoZSBbZ2dwbG90Ml0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvKSBwYWNrYWdlIGNyZWF0ZXMgcGxvdHMgYnkgdXNpbmcgbGF5ZXJzLiBOb3RpY2UgaW4gdGhlIGZvbGxvd2luZyBjb2RlIGhvdyB0aGVyZSBpcyBhIHBsdXMgc2lnbiBiZXR3ZWVuIHRoZSBgZ2dwbG90KClgIGZ1bmN0aW9uIGFuZCB0aGUgYGdlb21faGlzdG9ncmFtKClgIGZ1bmN0aW9uLiBXaXRoIGdncGxvdDIgd2Ugc2VsZWN0IHdoYXQgZGF0YSB3ZSB3b3VsZCBsaWtlIHRvIHBsb3QgdXNpbmcgdGhlIGZpcnN0IGZ1bmN0aW9uIChgZ2dwbG90KClgKSBhbmQgdGhlbiB3ZSBhZGQgb24gYWRkaXRpb25hbCBsYXllcnMgb2YgY29tcGxleGl0eSAodGhlc2UgbGF5ZXJzIGNhbiBldmVuIGludm9sdmUgZGlmZmVyZW50IGRhdGEpLiBJbiB0aGlzIGNhc2UgdGhlIGBnZW9tX2hpc3Ryb2dyYW0oKWAgZnVuY3Rpb24gaW5pdGlhdGVzIHRoZSBwbG90dGluZyBvZiBhIGhpc3RvZ3JhbSB3aXRoIHRoZSBkYXRhIHRoYXQgd2FzIGlkZW50aWZpZWQgaW4gdGhlIGBnZ3Bsb3QoKWAgZnVuY3Rpb24uIFdlIHdpbGwgc2VlIGxhdGVyIGhvdyB3ZSBjYW4gYWRkIG1hbnkgbGF5ZXJzIHRvIHBsb3RzIHdpdGggYGdncGxvdDJgLiBGb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBvbiB1c2luZyBnZ3Bsb3QyLCBzZWUgdGhpcyBbY2FzZSBzdHVkeV0oaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvL29jcy1oZWFsdGhleHBlbmRpdHVyZS9vY3MtaGVhbHRoZXhwZW5kaXR1cmUuaHRtbCkuCgpgYGB7cn0KCm5vcm1fQk1JX2V4X2RhdGEgJT4lIAogIGdncGxvdDI6OmdncGxvdChhZXMoeCA9IG5vcm1fZGF0YSkpICsgCiAgZ2dwbG90Mjo6Z2VvbV9oaXN0b2dyYW0oKSAKIyBXZSBhcmUgdXNpbmcgdGhlIGNvbHVtbiBjYWxsZWQgbm9ybV9kYXRhIHdpdGhpbiBub3JtX0JNSV9leF9kYXRhCiMgV2l0aCBnZ3Bsb3QyIHdlIG11c3QgZmlyc3Qgc3BlY2lmeSB0aGUgZGF0YSB3aXRoIGdncGxvdCgpIAojIFRoZSBnZW9tX2hpc3RvZ3JhbSgpIGZ1bmN0aW9uIHNwZWNpZmllcyB3aGF0IHR5cGUgb2YgcGxvdCB0byBjcmVhdGUKYGBgCgpMZXQncyBzZWUgaG93IG91ciBkYXRhIGxvb2tzOgpgYGB7cn0KQk1JX2xvbmclPiUgCiAgZ2dwbG90KGFlcyh4ID0gQk1JKSkgKyAKICBnZW9tX2hpc3RvZ3JhbSgpIAoKYGBgCgpPSywgc28gdGhlIGRhdGEgbG9va3MgbGlrZSBpdCBpcyB3aGF0IHdlIGNhbGwgPGI+cmlnaHQtc2tld2VkPC9iPiBiZWNhdXNlIHRoZSB0YWlsIG9mIHRoZSBkaXN0cmlidXRpb24gaXMgbG9uZ2VyIG9uIHRoZSByaWdodCBzaWRlIChpbiBvdGhlciB3b3JkcywgaXQgaXMgYSBiaXQgd2lkZXIgb24gdGhhdCBzaWRlKSwgYnV0IGl0IGxvb2tzIGZhaXJseSBub3JtYWxseSBkaXN0cmlidXRlZC4KCklmIHdlIHBhcnNlIG91ciBkYXRhLCB3aGF0IGRvZXMgaXQgbG9vayBsaWtlPyBUaGUgZWFzaWVzdCB3YXkgdG8gZG8gdGhpcyBpcyB0byB1c2Ugc29tZSBvdGhlciBmdW5jdGlvbnMgb2YgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlLCBwYXJ0aWN1bGFybHkgdGhlIGBmYWNldF93cmFwKClgIGZ1bmN0aW9uLCB3aGljaCB3aWxsIGFsbG93IHVzIHRvIGxvb2sgYXQgZGlmZmVyZW5jZXMgaW4gdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgQk1JIGRhdGEgYnkgeWVhciwgZ2VuZGVyLCBhbmQgcmVnaW9uLiBXZSBjYW4gc2VxdWVudGlhbGx5IGRpdmlkZSBvdXIgcGxvdHMgYnkgZGVlcGVyIGxldmVscyB1c2luZyBtdWx0aXBsZSB2YXJpYWJsZXMgYW5kIHRoZSBgK2AgcGx1cyBzaWduIHdpdGhpbiBgZmFjZXRfd3JhcCgpYC4KCmBgYHtyLCBldmFsID0gVFJVRX0KQk1JX2xvbmcgJT4lCiAgZ2dwbG90KGFlcyh4PUJNSSkpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBmYWNldF93cmFwKH4gU2V4KQoKQk1JX2xvbmcgJT4lCiAgZ2dwbG90KGFlcyh4PUJNSSkpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBmYWNldF93cmFwKH4gU2V4ICsgWWVhcikgCgpCTUlfbG9uZyAlPiUKICBnZ3Bsb3QoYWVzKHg9Qk1JKSkgKwogIGdlb21faGlzdG9ncmFtKCkgKwogIGZhY2V0X3dyYXAofiBTZXggKyBZZWFyICsgUmVnaW9uKSAKCmBgYAoKT0ssIHNvIHNvbWUgb2YgdGhlc2UgcGxvdHMgbG9vayBwcmV0dHkgc2ltaWxhciB0byBvdXIgbm9ybWFsIGRpc3RyaWJ1dGlvbiBwbG90LCBsaWtlIHRoZSBXb21lbiAyMDE3IFVyYmFuIHBsb3QgKGFsdGhvdWdoIGl0IGlzIHJpZ2h0LXNrZXdlZCkuCkhvd2V2ZXIgc29tZSBvZiB0aGUgb3RoZXIgcGxvdHMsIGxpa2UgdGhlIE1lbiAyMDE3IFVyYmFuIHBsb3QsIGxvb2sgdmVyeSBkaWZmZXJlbnQuIAoKIyMjIFF1YW50aWxlLVF1YW50aWxlIFBsb3RzCgpMZXQncyB1c2UgYSBtZXRob2QgY2FsbGVkIHRoZSAgcXVhbnRpbGUtcXVhbnRpbGUgcGxvdCB0byBkZXRlcm1pbmUgaWYgdGhlIGRhdGEgaXMgaW5kZWVkIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBUaGVzZSBwbG90cyBhcmUgY2FsbGVkIDxiPlEtUSBwbG90czwvYj4uIFRoaXMgbWV0aG9kIGFsbG93cyB1cyB0byB0ZXN0IHRoZSBmaXQgb2Yga25vd24gdGhlb3JldGljYWwgZGlzdHJpYnV0aW9ucyAobGlrZSB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbikgd2l0aCBvdXIgb2JzZXJ2ZWQgZGlzdHJpYnV0aW9uLiBUbyBkbyB0aGlzIHdlIHdpbGwgcGxvdCB0aGUgcXVhbnRpbGVzIG9mIG91ciBkYXRhIG9uIHRoZSB5LWF4aXMgYW5kIHRoZSBxdWFudGlsZXMgb2YgdGhlIHRoZW9yZXRpY2FsIG5vcm1hbCBkaXN0cmlidXRpb24gb24gdGhlIHgtYXhpcy4gSWYgdGhlIHF1YW50aWxlcyBsaW5lIHVwIHRoZW4gd2UgY2FuIHNheSB0aGF0IG91ciBkYXRhIGlzIGZhaXJseSBub3JtYWwuIFdoYXQgZXhhY3RseSBpcyBhIDxiPnF1YW50aWxlPC9iPj8gVGhpcyBpcyBhIGRpdmlzaW9uIG9mIHRoZSBkYXRhIGRpc3RyaWJ1dGlvbiBpbnRvIHJvdWdobHkgZXF1YWwgcG9ydGlvbnMuCgpIZXJlIGlzIGFuIGV4YW1wbGUgb2YgYSBRLVEgcGxvdCBmb3IgdGhlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIGRhdGEgdGhhdCB3ZSBqdXN0IGNyZWF0ZWQgdXNpbmcgdGhlIGBzdGF0X3FxKClgIGZ1bmN0aW9uIG9mICB0aGUgYGdncGxvdDJgIHBhY2thZ2U6CgpgYGB7cn0KCm5vcm1fQk1JX2V4X2RhdGEgJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGUgPW5vcm1fZGF0YSkpICsKICBzdGF0X3FxKCkgKyAjIHRvIGFkZCB0aGUgbGluZSB3ZSBuZWVkIHRvIGFsc28gaW5jbHVkZSBzdGF0X3FxX2xpbmUoKQogIHN0YXRfcXFfbGluZSgpCgoKCmBgYAoKSGVyZSB3ZSBjYW4gc2VlIHRoYXQgdGhlIHF1YW50aWxlcyBhcmUgZmFpcmx5IHNpbWlsYXIgYmV0d2VlbiB0aGUgb2JzZXJ2ZWQgYW5kIHRoZW9yZXRpY2FsIGRhdGEuIFdlIHNlZSB0aGF0IHRoZSBwb2ludHMgbW9zdGx5IGZhbGwgb24gdGhlIGxpbmUsIGhvd2V2ZXIgdGhlcmUgYXJlIHNvbWUgcG9pbnRzIHRoYXQgYXJlIGEgYml0IGZ1cnRoZXIgZnJvbSB0aGUgbGluZSBhcyB3ZSBnZXQgdG8gdGhlIGV4dHJlbWUgcXVhbnRpbGVzLiBOb3RpY2UgdGhhdCB0aGUgc2FtcGxlIHF1YW50aWxlcyAod2hpY2ggd2lsbCBiZSBmYWlybHkgc2ltaWxhciB0byBvdXIgcmVhbCBCTUkgZGF0YSBxdWFudGlsZXMpIG9uIHRoZSB5LWF4aXMgaGFzIHRoZSBzYW1lIHJhbmdlIGFzIHRoZSB2YWx1ZXMgdGhhdCB3ZSBjcmVhdGVkLiBTbyB2YWx1ZXMgdGhhdCBhcmUgYmVsbG93IDIyIGZvciBleGFtcGxlIGFyZSByZXByZXNlbnRlZCBhcyB0aGUgcG9pbnRzIGJlbGxvdyAyMiBvbiB0aGUgeS1heGlzLiBBcyBleHBlY3RlZCB3ZSBzZWUgdGhhdCBhYm91dCBoYWxmIHRoZSBwb2ludHMgYXJlIGJlbGxvdyBvdXIgbWVhbiBvZiAyNC4KCklmIHdlIHdlcmUgdG8gdXNlIGRpZmZlcmVudCBkYXRhIHRoYXQgaGFkIGEgcmFuZ2Ugb2YgZGlmZmVyZW50IHZhbHVlcyBvdXIgeS1heGlzIHdvdWxkIHNoaWZ0IGFjY29yZGluZyB0byB0aGUgcmFuZ2Ugb2YgdmFsdWVzLiBGb3IgZXhhbXBsZSB0aGUgT3JhbmdlIGRhdGEgd2l0aGluIHRoZSBpbnN0YWxsYXRpb24gb2YgUiBpbmNsdWRlcyBkYXRhIGFib3V0IHRoZSBjaXJjdW1mZXJlbmNlIG9mIG9yYW5nZSB0cmVlcyBpbiBtaWxsaW1ldGVycy4gSGVyZSB3ZSBjYW4gc2VlIHRoYXQgdGhlIHF1YW50aWxlcyBhcmUgcXVpdGUgZGlmZmVyZW50IGJ1dCByZWZsZWN0IHRoZSByYW5nZSBvZiBvcmFuZ2UgdHJlZSBjaXJjdW1mZXJlbmNlcy4KYGBge3J9CnJhbmdlKE9yYW5nZSRjaXJjdW1mZXJlbmNlKQpPcmFuZ2UlPiUKICBnZ3Bsb3QoYWVzKHNhbXBsZSA9Y2lyY3VtZmVyZW5jZSkpICsKICBzdGF0X3FxKCkgKyAjIHRvIGFkZCB0aGUgbGluZSB3ZSBuZWVkIHRvIGFsc28gaW5jbHVkZSBzdGF0X3FxX2xpbmUoKQogIHN0YXRfcXFfbGluZSgpCmBgYAoKCkxldCdzIHRha2UgYSBsb29rIGF0IG91ciBCTUkgZGF0YToKCmBgYHtyfQoKQk1JX2xvbmcgJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGUgPUJNSSkpICsKICBzdGF0X3FxKCkgKyAjIHRvIGFkZCB0aGUgbGluZSB3ZSBuZWVkIHRvIGFsc28gaW5jbHVkZSBzdGF0X3FxX2xpbmUoKQogIHN0YXRfcXFfbGluZSgpICsKICBmYWNldF93cmFwKH4gU2V4ICsgWWVhciArIFJlZ2lvbikKYGBgClRoaXMgaXMgYSBsaXR0bGUgaGFyZCB0byBzZWUsIHNvbWUgcGxvdHMgbG9vayBwcmV0dHkgZ29vZCwgYnV0IHdoaWxlIG90aGVycyBzZWVtIHRvIGJlIHNrZXdlZCwgbGV0cyB0YWtlIGEgY2xvc2VyIGxvb2suCgpGb3IgdGhlIHNha2Ugb2Ygc2ltcGxpY2l0eSwgd2UgYXJlIGdvaW5nIHRvIGZvY3VzIG9uIHRoZSBkYXRhIGZyb20gdGhlIHdvbWVuLiAgVGhpcyBpcyBiZWNhdXNlIHdvbWVuIHdlcmUgaWRlbnRpZmllZCBpbiB0aGUgcGFwZXIgdG8gaGF2ZSBsYXJnZXIgaW5jcmVhc2VzIGluIEJNSS4gSWYgd2Ugd2FudCB0byBwZXJmb3JtIHRlc3RzIG9uIHRoZXNlIGdyb3VwcyBzcGVjaWZpY2FsbHksIHRoZW4gd2UgbmVlZCB0byBrbm93IGhvdyB0aGlzIGRhdGEgbG9va3MuCgpgYGB7cn0KCkJNSV9sb25nICU+JQogIGZpbHRlcihTZXggPT0gIldvbWVuIikgJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGUgPUJNSSkpICsKICBzdGF0X3FxKCkgKyAjIHRvIGFkZCB0aGUgbGluZSB3ZSBuZWVkIHRvIGFsc28gaW5jbHVkZSBzdGF0X3FxX2xpbmUoKQogIHN0YXRfcXFfbGluZSgpICsKICBmYWNldF93cmFwKH4gWWVhciArIFJlZ2lvbikKYGBgCgoKV2hhdCBhYm91dCBieSByZWdpb24gYW5kIHllYXI/IElmIHdlIGNvbXBhcmUgdGhlc2UgZGF0YSB0aGVuIHdlIG5lZWQgdG8gbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGVhY2ggb2YgdGhlc2Ugc3Vic2V0cy4KCldlIGNhbiBzZWUgdGhhdCBhdCB0aGUgZXh0cmVtZXMgb2Ygb3VyIHF1YW50aWxlcywgZm9yIG1vc3Qgb2Ygb3VyIGRhdGEsIG91ciB0YWlscyBhcmUgbm90IHZlcnkgc2ltaWxhciB0byB0aGUgdGhlb3JldGljYWwgZGlzdHJpYnV0aW9uLiBUaGUgcnVyYWwgZGF0YSBsb29rcyBtb3JlIG5vcm1hbCB0aGFuIHRoZSB1cmJhbiBkYXRhLCBidXQgaWYgd2Ugd2VyZSB0byB1c2Ugc3RhdGlzdGljYWwgdGVzdHMgdGhhdCByZWx5IG9uIG5vcm1hbGl0eSwgdGhpcyB3b3VsZCByZXF1aXJlIHRoYXQgYm90aCBncm91cHMgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKRmluYWxseSwgc29tZSBzdGF0aXN0aWNpYW5zIGFsc28gdXNlIHRoZSBTaGFwaXJvLVdpbGsgdGVzdCBmb3Igbm9ybWFsaXR5IHdoZW4gdGhlIFEtUSBwbG90IGlzIGEgYml0IHVuY2xlYXIuIE1hbnkgc3RhdGlzdGljaWFucyBob3dldmVyIHdvdWxkIGNvbmNsdWRlIGZyb20gdGhlIFEtUSBwbG90cyB0aGF0IG5vcm1hbGl0eSBhcHBlYXJzIHRvIGJlIHZpb2xhdGVkIGluIG91ciBkYXRhLiAKCiMjIyBTaGFwaXJvLVdpbGsgdGVzdAoKRm9yIGlsbHVzdHJhdGl2ZSBwdXJwb3NlcyB3ZSB3aWxsIHNob3cgaG93IHdlIGNhbiB1c2UgdGhlIGBkcGx5cmAgYHN1bW1hcml6ZSgpYCBhbmQgYGdyb3VwX2J5KClgIGZ1bmN0aW9ucyB0byBwZXJmb3JtIHRoZSBTaGFwaXJvLVdpbGsgdGVzdCBmb3IgYWxsIHRoZSBzdWJzZXRzIHdlIGFyZSBpbnRlcmVzdGVkIGluLgoKYGBge3J9Cgpub3JtX0JNSV9leF9kYXRhJG5vcm1fZGF0YSAlPiUgCiAgc2hhcGlyby50ZXN0KCkgCiMgZXhhbXBsZSBvZiB0aGUgdGVzdCBvdXRwdXQgZm9yIG5vcm1hbCBkYXRhIC0gdGhlIHAgdmFsdWUgaXMgbm90IDwgMC4wNQoKQk1JX2xvbmcgJT4lIAogIGZpbHRlcihTZXggPT0gIldvbWVuIikgJT4lIAogIGdyb3VwX2J5KFllYXIsIFJlZ2lvbikgJT4lIAogIHN1bW1hcml6ZShzaGFwaXJvX3Rlc3QgPSBzaGFwaXJvLnRlc3QoQk1JKSRwLnZhbHVlKQoKYGBgCgpXZSBzZWUgdGhhdCBhbGwgdGhlIGRhdGEgZG9lcyBub3QgYXBwZWFyIHRvIGJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKIyMgRGF0YSBBbmFseXNpcwoKV2UgY2FuIHVzZSBzdGF0aXN0aWNhbCB0ZXN0cyBsaWtlIHRoZSBzdHVkZW50IHQtdGVzdCB0byBkZXRlcm1pbmUgaWYgdHdvIG1lYW5zIGFyZSBzaWduaWZpY2FudGx5IGRpZmZlcmVudC4KCldpdGggdGhlIHQtdGVzdCwgd2UgcGVyZm9ybSB3aGF0IGlzIGNhbGxlZCA8Yj4gdHdvIG1lYW5zIGh5cG90aGVzaXMgdGVzdHMgPC9iPi4KV2UgZGVmaW5lIHdoYXQgaXMgY2FsbGVkIHRoZSA8Yj4gbnVsbCBoeXBvdGhlc2lzIDwvYj4sIHdoaWNoIGlzIHdoYXQgd2UgYXNzdW1lIGJ5IGRlZmF1bHQgb3IgdGhlIGJhc2VsaW5lLCB0aGF0IHRoZXJlIGlzIG5vIGRpZmZlcmVuY2UgaW4gdGhlIHR3byBtZWFuczoKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBIbzogzrwxID0gzrwyCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIM68MSBpcyB0aGUgbWVhbiBvZiBvbmUgZ3JvdXAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIM68MiBpcyB0aGUgbWVhbiBvZiB0aGUgb3RoZXIgZ3JvdXAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIApUaHVzIGxpa2UgaW4gbGF3LCB3ZSBhY2NlcHQgdGhpcyBudWxsIGh5cG90aGVzaXMsIHVubGVzcyB3ZSBoYXZlIGVub3VnaCBldmlkZW5jZSB0byBzdWdnZXN0IHRoYXQgd2Ugc2hvdWxkIHJlamVjdCBpdCAtIHNpbWlsYXIgdG8gdGhlIGlkZWEgdGhhdCB3ZSBieSBkZWZhdWx0IGFzc3VtZSB0aGF0IGluZGl2dWRhbHMgYXJlIG5vdCBndWlsdHksIHVudGlsbCBwcm92ZW4gb3RoZXJ3aXNlLiBJZiB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcywgd2UgdGhlbiBhY2NlcHQgYW4gPGI+IGFsdGVybmF0aXZlIGh5cG90aGVzaXMgPC9iPiwgdGhpcyBjYW4gdmFyeSBmb3IgZGlmZmVyZW50IHN0YXRpc3RpY2FsIHRlc3RzLCBidXQgaW4gdGhlIGNhc2Ugb2YgdGhlIHQtdGVzdCB3ZSBldmFsdWF0ZSBpZiB0aGUgdHdvIG1lYW5zIGFyZSBub3QgZXF1YWw6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEhhOiDOvDEg4omgIM68MgogICAgCgpXZSBhcmUgaW50ZXJlc3RlZCBpbiBjb21wYXJpbmcgdGhlIG1lYW5zIG9mIGZlbWFsZSBydXJhbCBhbmQgdXJiYW4gQk1JIG1lYXN1cmVtZW50cyBmb3IgYm90aCB5ZWFycy4gCgpUaGVyZSBhcmUgdHdvIHBvc3NpYmxlIGNsYXNzZXMgb2Ygc3RhdGlzdGljYWwgdGVzdHMgdGhhdCB3ZSBjb3VsZCBydW4gdG8gY29tcGFyZSB0aGUgbWVhbnMgb2YgdGhlc2UgdHdvIGdyb3VwczoKCjEpIFBhcmFtZXRyaWMKMikgbm9ucGFyYW1ldHJpYwoKIyMjIFBhcmFtZXRyaWMgdHdvIHNhbXBsZSBtZWFuIHRlc3RzCgpPZnRlbiB3aGVuIGNvbXBhcmluZyB0d28gZ3JvdXBzIHdlIG1pZ2h0IHBlcmZvcm0gYSB0d28gc2FtcGxlIHQtdGVzdCB0byBkZXRlcm1pbmUgaWYgdGhlIG1lYW5zIG9mIGVhY2ggZ3JvdXAgaXMgZGlmZmVyZW50LiBUaGUgdHdvIHNhbXBsZSB0LXRlc3QgaG93ZXZlciwgcmVsaWVzIG9uIHNldmVyYWwgPHN0cm9uZz5hc3N1bXB0aW9uczwvc3Ryb25nPjoKCjEpIFRoZSBkYXRhIGZvciBib3RoIGdyb3VwcyBpcyBub3JtYWxseSBkaXN0cmlidXRlZAoyKSBUaGUgdmFyaWFuY2Ugb2YgYm90aCBncm91cHMgaXMgc2ltaWxhcgozKSBUaGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpcyBzaW1pbGFyIGZvciBib3RoIGdyb3VwcyAtIHRodXMgdGhleSBhcmUgPGI+IGJhbGFuY2VkIDwvYj4KCklmIHRoZXNlIGFzc3VtcHRpb25zIGFyZSB2aW9sYXRlZCwgdGhpcyBkb2Vzbid0IG5lY2Vzc2FyaWx5IG1lYW4gd2UgY2FuJ3QgcGVyZm9ybSBhIHQtdGVzdC4gSXQganVzdCBtZWFucyB3ZSBtYXkgaGF2ZSB0byB0cmFuc2Zvcm0gdGhlIGRhdGEgdG8gbWFrZSBpdCBub3JtYWxseSBkaXN0cmlidXRlZCBhbmQgd2UgbWF5IG5lZWQgdG8gcGVyZm9ybSB0aGUgdC10ZXN0IGluIGEgc3BlY2lhbCB3YXkgdG8gYWNjb3VudCBmb3IgdGhlIGRpZmZlcmVuY2UgaW4gdGhlIHZhcmlhbmNlIGluIHRoZSB0d28gZ3JvdXBzLiBBbHRlcm5hdGl2ZWx5LCB3ZSBjYW4gdXNlIGEgbm9ucGFyYW1ldHJpYyB0ZXN0IGxpa2UgdGhlIFdpbGNveG9u4oCTTWFubuKAk1doaXRuZXkgKFdNVykgdGVzdC4gV2Ugd2lsbCBleHBsb3JlIHRoZXNlIG9wdGlvbnMuCgpPdXIgZGF0YSBoYXMgYSBiYWxhbmNlIG9mIG9ic2VydmF0aW9ucyBmb3IgYm90aCBncm91cHMgLSBpbiBmYWN0IHRoZXkgYXJlIGVxdWFsLCB0aHVzIHRoYXQgYXNzdW1wdGlvbiBpcyBub3QgdmlvbGF0ZWQuCklmIGl0IHdlcmUgdmlvbGF0ZWQsIHdlIHdvdWxkIHdhbnQgdG8gY29uc2lkZXIgdXNpbmcgcGVybXV0YXRpb24gbWV0aG9kcy4gVG8gbGVhcm4gbW9yZSBhYm91dCB0aGVzZSBtZXRob2RzIHNlZSBbaGVyZV0oaHR0cHM6Ly9qaHUtYWR2ZGF0YXNjaS5naXRodWIuaW8vMjAxOS9sZWN0dXJlcy8yMS1yZXNhbXBsaW5nLXRlY2huaXF1ZXMuaHRtbCkuCgpJZiB3ZSBuZWVkZWQgdG8gY2hlY2sgaWYgb3VyIHNhbXBsZXMgd2VyZSBpbWJhbGFuY2VkLCB3ZSBjb3VsZCB1c2UgdGhlIGB0YWJsZSgpYCBmdW5jdGlvbjoKCmBgYHtyfQp0YWJsZShCTUlfbG9uZyRTZXgsIEJNSV9sb25nJFJlZ2lvbiwgQk1JX2xvbmckWWVhcikKYGBgCgpXZSBjYW4gc2VlIHRoYXQgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgZm9yIGVhY2ggcG9zc2libGUgZ3JvdXAgb2YgaW50ZXJlc3QgaXMgdGhlIHNhbWUuCgpUaGUgdC10ZXN0IGlzIGFsc28gZmFpcmx5IHJvYnVzdCB0byBub24tbm9ybWFsaXR5IGlmIHRoZSBkYXRhIGlzIHJlbGF0aXZlbHkgbGFyZ2UsIGFuZCB3ZSBoYXZlIGFuIG4gb2YgMjAwLCB3aGljaCBzaG91bGQgYmUgc3VmZmljaWVudCBidXQgbGV0J3MgaW52ZXN0aWdhdGUgdGhlIG5vbnBhcmFtZXRyaWMgdGVzdHMgZnVydGhlci4gCgoKT2Z0ZW4gd2Ugd291bGQgY2hlY2sgaWYgdGhlIHZhcmlhbmNlIG9mIHRoZSBydXJhbCBhbmQgdXJiYW4gZGF0YSBpcyBlcXVhbCB1c2luZyB0aGUgYHZhci50ZXN0KClgIGZ1bmN0aW9uLiBIb3dldmVyIHRoaXMgaXMgYW4gRiB0ZXN0IGFuZCBhc3N1bWVzIHRoYXQgdGhlIGRhdGEgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuIEluc3RlYWQgd2Ugd2lsbCB1c2UgdGhlIGBtb29kLnRlc3QoKWAgZnVuY3Rpb24gd2hpY2ggcGVyZm9ybXMgdGhlIE1vb2QncyB0d28tc2FtcGxlIHRlc3QgZm9yIGEgZGlmZmVyZW5jZSBpbiBzY2FsZSBwYXJhbWV0ZXJzIGFuZCBkb2VzIG5vdCBhc3N1bWUgdGhhdCB0aGUgZGF0YSBpcyBub3JtYWxseSBkaXN0cmlidXRlZC4gV2Ugd2lsbCBhbHNvIGludHJvZHVjZSB0aGUgYHB1bGwoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4KCmBgYHtyfQoKI3B1bGwoKSB3aWxsIGFsbG93IHVzIHRvIHRha2UgdGhlIEJNSSBjb2x1bW4gYWZ0ZXIgd2UgZmlsdGVyIEJNSV9sb25nCgptb29kLnRlc3QoZHBseXI6OnB1bGwoZmlsdGVyKEJNSV9sb25nLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWWVhciA9PSAiMjAxNyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJlZ2lvbiA9PSAiUnVyYWwiKSwgQk1JKSwgCiAgICAgICAgICBkcGx5cjo6cHVsbChmaWx0ZXIoQk1JX2xvbmcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2V4ID09ICJXb21lbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFllYXIgPT0gIjIwMTciLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSZWdpb24gPT0gIlVyYmFuIiksIEJNSSkpCiMgcCB2YWx1ZSA8LjA1LCBjb25jbHVkZSB0aGF0IHZhcmlhbmNlIGlzIG5vdCBlcXVhbAojIHJlamVjdCB0aGUgbnVsbDogbm8gZGlmZmVyZW5jZSBpbiB0aGUgdmFyaWFuY2Ugb2YgdGhlIGRpc3RyaWJ1dGlvbnMKCm1vb2QudGVzdChwdWxsKGZpbHRlcihCTUlfbG9uZywgU2V4ID09ICJXb21lbiIsIAogICAgICAgICAgICAgICAgICAgICAgWWVhciA9PSAiMTk4NSIsIAogICAgICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJSdXJhbCIpLCBCTUkpLCAKICAgICAgICAgIHB1bGwoZmlsdGVyKEJNSV9sb25nLCAKICAgICAgICAgICAgICAgICAgICAgIFNleCA9PSAiV29tZW4iLCAKICAgICAgICAgICAgICAgICAgICAgIFllYXIgPT0gIjE5ODUiLCAKICAgICAgICAgICAgICAgICAgICAgIFJlZ2lvbiA9PSAiVXJiYW4iKSwgQk1JKSkKIyBwIHZhbHVlIDwuMDUsIGNvbmNsdWRlIHRoYXQgdmFyaWFuY2UgaXMgbm90IGVxdWFsCiMgcmVqZWN0IHRoZSBudWxsOiBubyBkaWZmZXJlbmNlIGluIHRoZSB2YXJpYW5jZSBvZiB0aGUgZGlzdHJpYnV0aW9ucwoKbW9vZC50ZXN0KHB1bGwoZmlsdGVyKEJNSV9sb25nLCAKICAgICAgICAgICAgICAgICAgICAgIFNleCA9PSAiV29tZW4iLCAKICAgICAgICAgICAgICAgICAgICAgIFllYXIgPT0gIjE5ODUiLCAKICAgICAgICAgICAgICAgICAgICAgIFJlZ2lvbiA9PSAiUnVyYWwiKSwgQk1JKSwgCiAgICAgICAgICBwdWxsKGZpbHRlcihCTUlfbG9uZywgU2V4ID09ICJXb21lbiIsIAogICAgICAgICAgICAgICAgICAgICAgWWVhciA9PSAiMjAxNyIsIAogICAgICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJSdXJhbCIpLCBCTUkpKQojIHAgdmFsdWUgPi4wNSwgY29uY2x1ZGUgdGhhdCB2YXJpYW5jZSBpcyBlcXVhbAojIGFjY2VwdCB0aGUgbnVsbDogbm8gZGlmZmVyZW5jZSBpbiB0aGUgdmFyaWFuY2Ugb2YgdGhlIGRpc3RyaWJ1dGlvbnMKCm1vb2QudGVzdChwdWxsKGZpbHRlcihCTUlfbG9uZywgCiAgICAgICAgICAgICAgICAgICAgICBTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICAgICBZZWFyID09ICIxOTg1IiwgCiAgICAgICAgICAgICAgICAgICAgICBSZWdpb24gPT0gIlVyYmFuIiksIEJNSSksIAogICAgICAgICAgcHVsbChmaWx0ZXIoQk1JX2xvbmcsIFNleCA9PSAiV29tZW4iLCAKICAgICAgICAgICAgICAgICAgICAgIFllYXIgPT0gIjIwMTciLCAKICAgICAgICAgICAgICAgICAgICAgIFJlZ2lvbiA9PSAiVXJiYW4iKSwgQk1JKSkKIyBwIHZhbHVlID4uMDUsIGNvbmNsdWRlIHRoYXQgdmFyaWFuY2UgaXMgZXF1YWwKIyBhY2NlcHQgdGhlIG51bGw6IG5vIGRpZmZlcmVuY2UgaW4gdGhlIHZhcmlhbmNlIG9mIHRoZSBkaXN0cmlidXRpb25zCgpgYGAKCk91ciBwIHZhbHVlIGlzIGxlc3MgdGhhbiAuMDUgZm9yIGJvdGggdGVzdHMsIHRodXMgd2UgcmVqZWN0IG91ciBudWxsIGh5cG90aGVzaXMgdGhhdCB0aGVyZSBpcyBubyBkaWZmZXJlbmNlIGluIHRoZSB2YXJpYW5jZS4gVGhlcmVmb3JlLCB3ZSBjb25jbHVkZSB0aGF0IHRoZSB2YXJpYW5jZSBpcyBub3QgZXF1YWwgYW5kIHRoYXQgb3VyIGRhdGEgYWxzbyB2aW9sYXRlcyB0aGlzIGFzc3VtcHRpb24uCgpXZSB3aWxsIHBlcmZvcm0gYSBzcGVjaWFsIHQudGVzdCB3aGVyZSB3ZSBhY2NvdW50IGZvciB0aGUgZmFjdCB0aGF0IG91ciB2YXJpYW5jZSBpcyBub3QgZXF1YWwuIAoKQW5vdGhlciBpbXBvcnRhbnQgY29uc2lkZXJhdGlvbiBpcyB0aGF0IHRoZSBkYXRhIGlzIHdoYXQgd2UgY2FsbCA8Yj5wYWlyZWQ8L2I+LiBNZWFuaW5nIHRoZSBtZWFzdXJlbWVudHMgZnJvbSB0aGUgcnVyYWwgYW5kIHVyYmFuIGFyZWFzIGFyZSBub3QgaW5kZXBlbmRlbnQuIFRoYXQgaXMgYmVjYXVzZSB3ZSBoYXZlIGEgcnVyYWwgYW5kIHVyYmFuIG1lYXN1cmVtZW50IG1lYW4gZm9yIG5lYXJseSBldmVyeSBjb3VudHJ5LiBUaHVzIHRoZXNlIHZhbHVlcyBtYXkgYmUgbW9yZSBzaW1pbGFyIHRvIG9uZSBhbm90aGVyIGlmIHRoZXkgY29tZSBmcm9tIHRoZSBzYW1lIGNvdW50cnkuCgpgYGB7cn0KCnQudGVzdChwdWxsKGZpbHRlcihCTUlfbG9uZywgU2V4ID09ICJXb21lbiIsIAogICAgICAgICAgICAgICAgICAgWWVhciA9PSAiMjAxNyIsIAogICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJSdXJhbCIpLCBCTUkpLCAKICAgICAgIHB1bGwoZmlsdGVyKEJNSV9sb25nLCBTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICBZZWFyID09ICIyMDE3IiwgCiAgICAgICAgICAgICAgICAgICBSZWdpb24gPT0gIlVyYmFuIiksIEJNSSksIAogICAgICAgdmFyLmVxdWFsID0gRkFMU0UsIHBhaXJlZCA9IFRSVUUpCiMgbWVhbnMgYXJlIGRpZmZlcmVudCAtIHAgdmFsdWUgPC4wNSByZWplY3QgdGhlIG51bGw6IG5vIGRpZmZlcmVuY2UgaW4gdGhlIG1lYW5zCgp0LnRlc3QocHVsbChmaWx0ZXIoQk1JX2xvbmcsIFNleCA9PSAiV29tZW4iLCAKICAgICAgICAgICAgICAgICAgIFllYXIgPT0gIjE5ODUiLAogICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJSdXJhbCIpLCBCTUkpLCAKICAgICAgIHB1bGwoZmlsdGVyKEJNSV9sb25nLCBTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICBZZWFyID09ICIxOTg1IiwgCiAgICAgICAgICAgICAgICAgICBSZWdpb24gPT0gIlVyYmFuIiksIEJNSSksCiAgICAgICB2YXIuZXF1YWwgPSBGQUxTRSwgcGFpcmVkID0gVFJVRSkKIyBtZWFucyBhcmUgZGlmZmVyZW50IC0gcCB2YWx1ZSA8LjA1IHJlamVjdCB0aGUgbnVsbDogbm8gZGlmZmVyZW5jZSBpbiB0aGUgbWVhbnMKCnQudGVzdChwdWxsKGZpbHRlcihCTUlfbG9uZywgU2V4ID09ICJXb21lbiIsIAogICAgICAgICAgICAgICAgICAgWWVhciA9PSAiMTk4NSIsIAogICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJSdXJhbCIpLCBCTUkpLCAKICAgICAgIHB1bGwoZmlsdGVyKEJNSV9sb25nLCBTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICBZZWFyID09ICIyMDE3IiwgCiAgICAgICAgICAgICAgICAgICBSZWdpb24gPT0gIlJ1cmFsIiksIEJNSSksCiAgICAgICB2YXIuZXF1YWwgPSBUUlVFLCBwYWlyZWQgPSBUUlVFKQojIG1lYW5zIGFyZSBkaWZmZXJlbnQgLSBwIHZhbHVlIDwuMDUgcmVqZWN0IHRoZSBudWxsOiBubyBkaWZmZXJlbmNlIGluIHRoZSBtZWFucwoKdC50ZXN0KHB1bGwoZmlsdGVyKEJNSV9sb25nLCBTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICBZZWFyID09ICIxOTg1IiwgCiAgICAgICAgICAgICAgICAgICBSZWdpb24gPT0gIlVyYmFuIiksIEJNSSksIAogICAgICAgcHVsbChmaWx0ZXIoQk1JX2xvbmcsIFNleCA9PSAiV29tZW4iLCAKICAgICAgICAgICAgICAgICAgIFllYXIgPT0gIjIwMTciLCAKICAgICAgICAgICAgICAgICAgIFJlZ2lvbiA9PSAiVXJiYW4iKSwgQk1JKSwKICAgICAgIHZhci5lcXVhbCA9IFRSVUUsIHBhaXJlZCA9IFRSVUUpCiMgbWVhbnMgYXJlIGRpZmZlcmVudCAtIHAgdmFsdWUgPC4wNSByZWplY3QgdGhlIG51bGw6IG5vIGRpZmZlcmVuY2UgaW4gdGhlIG1lYW5zCiMgdGhlIHQgdmFsdWUgc2hvd3MgdXMgdGhhdCB0aGUgZGlyZWN0aW9uYWxpdHkgb2YgdGhlIGRpZmZlcmVuY2UKIyB0aGUgdCB2YWx1ZSB3YXMgbmVnYXRpdmUgdGh1cyBCTUkgd2FzIGxvd2VyIGluIDE5ODUgKDFzdCBncm91cCkgCiMgY29tcGFyZWQgdG8gMjAxNyAoMm5kIGdyb3VwKQoKCmBgYAoKIyMjIyB7LnF1ZXN0aW9uX2Jsb2NrfQo8dT5RdWVzdGlvbiBvcHBvcnR1bml0eTo8L3U+IApMb29raW5nIGF0IHRoZSB0IHZhbHVlLCB3YXMgZ2xvYmFsIEJNSSBsb3dlciBpbiBSdXJhbCBvciBVcmJhbiBhcmVhcyBpbiAxOTg1PwoKIyMjIwoKTm93IHdlIHdpbGwgdHJ5IHRyYW5zZm9ybSBvdXIgZGF0YSB0byBtYWtlIGl0IG1vcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuIE9uZSB3YXkgdG8gZG8gdGhpcyBpcyB0byB0YWtlIHRoZSBsb2dhcml0aG0gb2YgdGhlIGRhdGEgdmFsdWVzLiBUaGVuIHdlIHdpbGwgc2VlIGhvdyB0aGlzIGluZmx1ZW5jZXMgdGhlIHJlc3VsdHMuIEFnYWluIHdlIHdpbGwgZm9jdXMgb24gdGhlIGRhdGEgZm9yIHdvbWVuLgoKYGBge3J9CgojIGNyZWF0ZSBhIG5ldyBjb2x1bW4gd2l0aCB0aGUgbG9nIHZlcnNpb24gb2YgdGhlIEJNSSB2YXJpYWJsZSB1c2luZyBtdXRhdGUoKQoKQk1JX2xvbmdfbG9nIDwtIG11dGF0ZShCTUlfbG9uZywgbG9nX0JNST1sb2cocHVsbChCTUlfbG9uZyxCTUkpKSkKCkJNSV9sb25nX2xvZyAlPiUKICBmaWx0ZXIoU2V4ID09ICJXb21lbiIpICU+JQogIGdncGxvdChhZXMoc2FtcGxlID1sb2dfQk1JKSkgKwogIHN0YXRfcXEoKSArICMgdG8gYWRkIHRoZSBsaW5lIHdlIG5lZWQgdG8gYWxzbyBpbmNsdWRlIHN0YXRfcXFfbGluZSgpCiAgc3RhdF9xcV9saW5lKCkgKwogIGZhY2V0X3dyYXAofiBZZWFyICsgUmVnaW9uKQoKQk1JX2xvbmdfbG9nICU+JSAKICBmaWx0ZXIoU2V4ID09ICJXb21lbiIpICU+JSAKICBncm91cF9ieShZZWFyLCBSZWdpb24pICU+JSAKICBzdW1tYXJpemUoc2hhcGlyb190ZXN0ID0gc2hhcGlyby50ZXN0KGxvZ19CTUkpJHAudmFsdWUpCgojIHJlY2FsbCB3aGF0IGl0IHdhcyBiZWZvcmUKQk1JX2xvbmcgJT4lIAogIGZpbHRlcihTZXggPT0gIldvbWVuIikgJT4lIAogIGdyb3VwX2J5KFllYXIsIFJlZ2lvbikgJT4lIAogIHN1bW1hcml6ZShzaGFwaXJvX3Rlc3QgPSBzaGFwaXJvLnRlc3QoQk1JKSRwLnZhbHVlKQoKCgpgYGAKClRoZSBkYXRhIGFwcGVhcnMgdG8gYmUgbW9yZSBzaW1pbGFyIHRvIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uLCBhbHRob3VnaCBub3QgcXVpdGUuIEFnYWluLCBvdXIgc2FtcGxlIHNpemUgb2YgMjAwIGlzIHF1aXRlIGxhcmdlIGFuZCB0aGUgdC10ZXN0IGlzIGdlbmVyYWxseSBxdWl0ZSByb2J1c3QgdG8gdmlvbGF0aW9ucyBvZiBub3JtYWxpdHkgd2l0aCBsYXJnZSBuLCB0aHVzIHRoZSBtb2RpZmllZCB0LXRlc3QgdG8gYWNjb3VudCBmb3IgdW5lcXVhbCB2YXJpYW5jZSBtaWdodCBiZSBhIGdvb2Qgb3B0aW9uIHVzaW5nIHRoZSBsb2cgbm9ybWFsaXplZCBkYXRhLCBhcyBpdCBpcyBhdCBsZWFzdCBtb3JlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKTGV0J3Mgc2VlIHRoZSByZXN1bHRzIG9mIHRoZSB0LXRlc3Qgd2l0aCB0aGUgdHJhbnNmb3JtZWQgZGF0YToKYGBge3J9Cgp0LnRlc3QocHVsbChmaWx0ZXIoQk1JX2xvbmdfbG9nLCBTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICBZZWFyID09ICIyMDE3IiwgCiAgICAgICAgICAgICAgICAgICBSZWdpb24gPT0gIlJ1cmFsIiksIGxvZ19CTUkpLCAKICAgICAgIHB1bGwoZmlsdGVyKEJNSV9sb25nX2xvZywgU2V4ID09ICJXb21lbiIsIAogICAgICAgICAgICAgICAgICAgWWVhciA9PSAiMjAxNyIsIAogICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJVcmJhbiIpLCBsb2dfQk1JKSwgCiAgICAgICB2YXIuZXF1YWwgPSBGQUxTRSwgcGFpcmVkID0gVFJVRSkKIyBtZWFucyBhcmUgZGlmZmVyZW50IC0gcCB2YWx1ZSA8LjA1IHJlamVjdCB0aGUgbnVsbDogbm8gZGlmZmVyZW5jZSBpbiB0aGUgbWVhbnMKCnQudGVzdChwdWxsKGZpbHRlcihCTUlfbG9uZ19sb2csIFNleCA9PSAiV29tZW4iLCAKICAgICAgICAgICAgICAgICAgIFllYXIgPT0gIjE5ODUiLCAKICAgICAgICAgICAgICAgICAgIFJlZ2lvbiA9PSAiUnVyYWwiKSwgbG9nX0JNSSksIAogICAgICAgcHVsbChmaWx0ZXIoQk1JX2xvbmdfbG9nLCBTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICBZZWFyID09ICIxOTg1IiwgCiAgICAgICAgICAgICAgICAgICBSZWdpb24gPT0gIlVyYmFuIiksIGxvZ19CTUkpLAogICAgICAgdmFyLmVxdWFsID0gRkFMU0UsIHBhaXJlZCA9IFRSVUUpCiMgbWVhbnMgYXJlIGRpZmZlcmVudCAtIHAgdmFsdWUgPC4wNSByZWplY3QgdGhlIG51bGw6IG5vIGRpZmZlcmVuY2UgaW4gdGhlIG1lYW5zCgp0LnRlc3QocHVsbChmaWx0ZXIoQk1JX2xvbmdfbG9nLCBTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICBZZWFyID09ICIxOTg1IiwgCiAgICAgICAgICAgICAgICAgICBSZWdpb24gPT0gIlJ1cmFsIiksIGxvZ19CTUkpLCAKICAgICAgIHB1bGwoZmlsdGVyKEJNSV9sb25nX2xvZywgU2V4ID09ICJXb21lbiIsIAogICAgICAgICAgICAgICAgICAgWWVhciA9PSAiMjAxNyIsIAogICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJSdXJhbCIpLCBsb2dfQk1JKSwKICAgICAgIHZhci5lcXVhbCA9IFRSVUUsIHBhaXJlZCA9IFRSVUUpCiMgbWVhbnMgYXJlIGRpZmZlcmVudCAtIHAgdmFsdWUgPC4wNSByZWplY3QgdGhlIG51bGw6IG5vIGRpZmZlcmVuY2UgaW4gdGhlIG1lYW5zCgp0LnRlc3QocHVsbChmaWx0ZXIoQk1JX2xvbmdfbG9nLCBTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICBZZWFyID09ICIxOTg1IiwgCiAgICAgICAgICAgICAgICAgICBSZWdpb24gPT0gIlVyYmFuIiksIGxvZ19CTUkpLCAKICAgICAgIHB1bGwoZmlsdGVyKEJNSV9sb25nX2xvZywgU2V4ID09ICJXb21lbiIsIAogICAgICAgICAgICAgICAgICAgWWVhciA9PSAiMjAxNyIsIAogICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJVcmJhbiIpLCBsb2dfQk1JKSwKICAgICAgIHZhci5lcXVhbCA9IFRSVUUsIHBhaXJlZCA9IFRSVUUpCiMgbWVhbnMgYXJlIGRpZmZlcmVudCAtIHAgdmFsdWUgPC4wNSByZWplY3QgdGhlIG51bGw6IG5vIGRpZmZlcmVuY2UgaW4gdGhlIG1lYW5zCgpgYGAKCldlIGNhbiBzZWUgdGhhdCBvdXIgcmVzdWx0cyBhcmUgcXVpdGUgc2ltaWxhciB0byB0aGF0IG9mIHRoZSBvcmlnaW5hbCBkYXRhLCBob3dldmVyIHRoZSB0IHZhbHVlcyBhcmUgc2xpZ2h0bHkgc21hbGxlci4gSW4gb3RoZXIgY2FzZXMgd2UgbWF5IHNlZSAgYSBtdWNoIG1vcmUgZHJhbWF0aWMgaW5mbHVlbmNlIG9mIHRyYW5zZm9ybWluZyBvdXIgZGF0YS4KCgpOb3csIGxldCdzIHRha2UgYSBsb29rIGF0IG5vbiBwYXJhbWV0cmljIHRlc3RzLCB3aGljaCBhcmUgYWxzbyBhIGdyZWF0IG9wdGlvbiB3aGVuIHRoZSBhc3N1bXB0aW9ucyBvZiB0aGUgdC10ZXN0IGFyZSB2aW9sYXRlZC4gCgojIyMgTm9ucGFyYW1ldHJpYyB0d28gc2FtcGxlIHRlc3RzCgpUaGVyZSBhcmUgdHdvIG5vbnBhcmFtZXRyaWMgb3B0aW9ucyB0byBjb25zaWRlciB3aGVuIHRoZSBhc3N1bXB0aW9ucyBvZiB0aGUgdC10ZXN0IGFyZSB2aW9sYXRlZC4gVGhlIFdpbGNveG9uIHNpZ25lZCByYW5rIHRlc3QgKGZvciBwYWlyZWQgZGF0YSAtIHRoZSBhbHRlcm5hdGl2ZSBpcyBXaWxjb3hvbiByYW5rIHN1bSB0ZXN0IGZvciBpbmRlcGVuZGVudCBzYW1wbGVzKSBhbmQgdGhlIFR3by1zYW1wbGUgS29sbW9nb3Jvdi1TbWlybm92IHRlc3QgYm90aCBkbyBub3QgYXNzdW1lIG5vcm1hbGl0eSAoaGFzIGJvdGggcGFpcmVkIGFuZCB1bnBhaXJlZCBtZXRob2RzKS4gVGh1cyB0aGVzZSB0ZXN0cyBzaG91bGQgYmUgY29uc2lkZXJlZCB3aGVuIHRoZSBkYXRhIG9mIGVpdGhlciBncm91cHMgZG9lcyBub3QgYXBwZWFyIHRvIGJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIGFuZCBwYXJ0aWN1bGFybHkgd2hlbiB0aGUgbnVtYmVyIG9mIHNhbXBsZXMgaXMgbG93LgoKSW1wb3J0YW50bHkgdGhlIEtvbG1vZ29yb3YtU21pcm5vdiAoS1MpIHRlc3QgZG9lcyBub3QgYXNzdW1lIG5vcm1hbGl0eSBvciBlcXVhbCB2YXJpYW5jZSwgd2hpbGUgdGhlIFdpbGNveG9uIHNpZ25lZCByYW5rIHRlc3QgZG9lcyBhc3N1bWUgZXF1YWwgdmFyaWFuY2UuIEhlcmUgaXMgaG93IHlvdSB3b3VsZCBwZXJmb3JtIHRoZXNlIHRlc3RzLiBIb3dldmVyIGluIG91ciBjYXNlLCBiZWNhdXNlIHRoZSB2YXJpYW5jZSBpcyBub3QgZXF1YWwgYmV0d2VlbiBzb21lIG9mIG91ciBncm91cHMgb2YgaW50ZXJlc3QsIHRoZSBLb2xtb2dvcm92LVNtaXJub3YgdGVzdCB3b3VsZCBiZSBtb3JlIGFwcHJvcHJpYXRlLiBCb3RoIHRoZSB0LXRlc3QgYW5kIHRoZSBLUyB0ZXN0IGV2YWx1YXRlIGlmIHRoZSBkaXN0cmlidXRpb25zIG9mIHRoZSB0d28gZ3JvdXBzIGFyZSBpZGVudGljYWwsIGhvd2V2ZXIgdGhlIEtTIHRlc3QgZG9lcyBub3QgcGFydGljdWxhcmx5IHRlc3QgYW55IGFzcGVjdCBvZiB0aGUgZGlzdHJpYnV0aW9uIGxpa2UgdGhlIG1lYW4sIHRoZXJlZm9yZSB0aGVyZSBhcmUgbm8gY29uZmlkZW5jZSBpbnRlcnZhbHMgaW4gdGhlIG91dHB1dCB1c2luZyB0aGlzIHRlc3QuIAoKYGBge3J9Cgprcy50ZXN0KHB1bGwoZmlsdGVyKEJNSV9sb25nLCBTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICAgWWVhciA9PSAiMjAxNyIsIAogICAgICAgICAgICAgICAgICAgIFJlZ2lvbiA9PSAiUnVyYWwiKSwgQk1JKSwgCiAgICAgICAgcHVsbChmaWx0ZXIoQk1JX2xvbmcsIFNleCA9PSAiV29tZW4iLCAKICAgICAgICAgICAgICAgICAgICBZZWFyID09ICIyMDE3IiwgCiAgICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJVcmJhbiIpLCBCTUkpLAogICAgICAgIHBhaXJlZCA9IFRSVUUpCgprcy50ZXN0KHB1bGwoZmlsdGVyKEJNSV9sb25nLCBTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICAgWWVhciA9PSAiMTk4NSIsIAogICAgICAgICAgICAgICAgICAgIFJlZ2lvbiA9PSAiUnVyYWwiKSwgQk1JKSwgCiAgICAgICAgcHVsbChmaWx0ZXIoQk1JX2xvbmcsIFNleCA9PSAiV29tZW4iLCAKICAgICAgICAgICAgICAgICAgICBZZWFyID09ICIxOTg1IiwgCiAgICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJVcmJhbiIpLCBCTUkpLAogICAgICAgIHBhaXJlZCA9IFRSVUUpCmBgYAoKCldoYXQgYWJvdXQgdGhlIGRpZmZlcmVuY2UgaW4gZmVtYWxlIEJNSSBmcm9tIDE5ODUgdG8gMjAxNyBmb3IgYm90aCByZWdpb25zPwpSZWNhbGwgdGhhdCB0aGUgdmFyaWFuY2Ugd2FzIGVxdWFsIGZvciB0aGVzZSBjb21wYXJpc29ucy4KCmBgYHtyfQoKd2lsY294LnRlc3QocHVsbChmaWx0ZXIoQk1JX2xvbmcsIFNleCA9PSAiV29tZW4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgWWVhciA9PSAiMTk4NSIsIAogICAgICAgICAgICAgICAgICAgICAgICBSZWdpb24gPT0gIlJ1cmFsIiksIEJNSSksCiAgICAgICAgICAgcHVsbChmaWx0ZXIoQk1JX2xvbmcsIFNleCA9PSAiV29tZW4iLCAKICAgICAgICAgICAgICAgICAgICAgICBZZWFyID09ICIyMDE3IiwgCiAgICAgICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJSdXJhbCIpLCBCTUkpLAogICAgICAgICAgIHBhaXJlZCA9IFRSVUUpCgp3aWxjb3gudGVzdChwdWxsKGZpbHRlcihCTUlfbG9uZywgU2V4ID09ICJXb21lbiIsIAogICAgICAgICAgICAgICAgICAgICAgICBZZWFyID09ICIxOTg1IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIFJlZ2lvbiA9PSAiVXJiYW4iKSwgQk1JKSwKICAgICAgICAgICBwdWxsKGZpbHRlcihCTUlfbG9uZywgU2V4ID09ICJXb21lbiIsIAogICAgICAgICAgICAgICAgICAgICAgIFllYXIgPT0gIjIwMTciLCAKICAgICAgICAgICAgICAgICAgICAgICBSZWdpb24gPT0gIlVyYmFuIiksIEJNSSksCiAgICAgICAgICAgcGFpcmVkID0gVFJVRSkKCmBgYApUaGVyZSBpcyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgYWNyb3NzIHRpbWUgZm9yIGJvdGggcmVnaW9ucywgYXMgd2Ugc2F3IHdpdGggdGhlIHQtdGVzdC4gVGhlcmUgaXMgYWxzbyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgYnkgcmVnaW9uIGZvciBlYWNoIHllYXIuIEhvd2V2ZXIsIHRoZSBwLXZhbHVlcyBhcmUgYSBiaXQgbGFyZ2VyIGZvciB0aGUgS1MgdGVzdCByZXN1bHRzIHRoYW4gd2Ugc2F3IHdpdGggdGhlIHQtdGVzdC4KCiMjIyBNdWx0aXBsZSBUZXN0aW5nIENvcnJlY3Rpb24KCkl0J3MgaW1wb3J0YW50IHRvIG5vdGUgdGhhdCB1bHRpbWF0ZWx5IHdlIHdhbnRlZCB0byB0ZXN0IDQgZGlmZmVyZW50IHRlc3RzOgoKMSkgSXMgdGhlcmUgYSBkaWZmZXJlbmNlIGluIG1lYW4gQk1JIGZvciB3b21lbiBiZXR3ZWVuIFJ1cmFsIGFuZCBVcmJhbiBhcmVhcyBpbiAxOTg1PwoyKSBJcyB0aGVyZSBhIGRpZmZlcmVuY2UgaW4gbWVhbiBCTUkgZm9yIHdvbWVuIGJldHdlZW4gUnVyYWwgYW5kIFVyYmFuIGFyZWFzIGluIDIwMTc/CjMpIElzIHRoZXJlIGEgZGlmZmVyZW5jZSBpbiBtZWFuIEJNSSBmb3Igd29tZW4gYmV0d2VlbiAxOTg1IGFuZCAyMDE3IGluIFJ1cmFsIGFyZWFzPwo0KSBJcyB0aGVyZSBhIGRpZmZlcmVuY2UgaW4gbWVhbiBCTUkgZm9yIHdvbWVuIGJldHdlZW4gMTk4NSBhbmQgMjAxNyBpbiBVcmJhbiBhcmVhcz8KCldoZW4gd2UgdGVzdCBtdWx0aXBsZSBxdWVzdGlvbnMgbGlrZSB0aGlzLCB3ZSBuZWVkIHRvIGNvcnJlY3QgZm9yIHRoZSBtdWx0aXBsZSB0ZXN0cyB0aGF0IHdlIGFyZSBwZXJmb3JtaW5nLgoKVGhlIG1vcmUgd2UgdGVzdCBkYXRhLCB0aGUgbW9yZSBsaWtlbHkgd2UgYXJlIHRvIHNlZSBhIHNpZ25pZmljYW50IGZpbmRpbmcganVzdCBieSBjaGFuY2UuCgpPbmUgd2F5IHRvIGRvIHRoaXMgaXMgdXNpbmcgdGhlIDxiPkJvbmZlcnJvbmk8L2I+IG1ldGhvZC4gCgpJbiB0aGlzIG1ldGhvZCB3ZSB3b3VsZCBkaXZpZGUgb3VyIHNpZ25pZmljYW5jZSB0aHJlc2hvbGQgKGdlbmVyYWxseSAwLjA1KSBieSB0aGUgbnVtYmVyIG9mIHRlc3RzLgoKYGBge3J9Ci4wNS80ICMgNCB0ZXN0cwpgYGAKCk91ciBuZXcgc2lnbmlmaWNhbmNlIHRocmVzaG9sZCBpcyBub3cgMC4wMTI1LiAKVGh1cyBvdXIgcC12YWx1ZXMgc2hvdWxkIGJlIGxlc3MgdGhhbiB0aGlzIHZhbHVlIGZvciB1cyB0byByZWplY3QgdGhlIG51bGwgdGhhdCB0aGVyZSBpcyBubyBkaWZmZXJlbmNlIGluIG1lYW5zLgpJbiBhbGwgY2FzZXMsIG91ciBwLXZhbHVlcyB3ZXJlIGxlc3MgdGhhbiAwLjAxMjUuClNvIHdlIHNlZSBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gdGhlIG1lYW5zIG9mIHRoZSBncm91cHMgYWZ0ZXIgbXVsdGlwbGUgdGVzdGluZyBjb3JyZWN0aW9uIGZvciBvdXIgZGlmZmVyZW50IHRlc3RzLgoKQWdhaW4sIGl0IHdvdWxkIGJlIHJlYXNvbmFibGUgdG8gdXNlIHRoZSB0LXRlc3QgYmVjYXVzZSBpdCBpcyByb2J1c3QgdG8gZGV2aWF0aW9ucyBpbiBub3JtYWxpdHkgd2hlbiBzYW1wbGVzIGFyZSByZWxhdGl2ZWx5IGxhcmdlLiAKV2UgY2FuIHNlZSB0aGF0IHdlIG9idGFpbmVkIHRoZSBzYW1lIHJlc3VsdHMgcmVnYXJkbGVzcyBvZiB0aGUgdGVzdCB0aGF0IHdlIHVzZWQuCkhvd2V2ZXIsIGlmIHNhbXBsZSBzaXplcyBhcmUgc21hbGwgKGdlbmVyYWxseSBzcGVha2luZyBuPDE1IGZvciBlYWNoIGdyb3VwKSwgdGhlbiB0aGVzZSBub25wYXJhbWV0cmljIG9wdGlvbnMgYXJlIHVzZWZ1bCB0byBrbm93LgoKVGhlIEQgdmFsdWVzIGluIHRoZSBvdXRwdXQgb2Ygb3VyIEtTIHRlc3RzLCBzaG93IHRoZSBtYWduaXR1ZGUgb2YgZGlzdGFuY2UgaW4gdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgZGlzdHJpYnV0aW9ucyBvZiB0aGUgZ3JvdXBzIHRlc3RlZC4KWW91IG1heSBub3RpY2UgdGhhdCB0aGUgRCB2YWx1ZSBpcyBsYXJnZXIgZm9yIHRoZSB0ZXN0cyBvZiBCTUkgYWNyb3NzIHRpbWUgcmF0aGVyIHRoZW4gYWNyb3NzIHJlZ2lvbi4KSW4gdGhlc2UgdGVzdHMgdGhlIHAtdmFsdWUgd2FzIGFsc28gc21hbGxlci4KCiMjIERhdGEgVmlzdWFsaXphdGlvbgoKQWdhaW4gd2Ugd2lsbCB1dGlsaXplIGBnZ3Bsb3QyYCB0byBjcmVhdGUgcGxvdHMgdG8gbG9vayBhdCB0aGUgZGlyZWN0aW9uYWwgYW5kIG1hZ25pdHVkZSBvZiB0aGUgZGlmZmVyZW5jZXMgaW4gQk1JIHdlIGFyZSBpbnRlcmVzdGVkIGluLiBJZiB5b3UgbmVlZCBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIHBsZWFzZSBzZWUgW2hlcmVdKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtaGVhbHRoZXhwZW5kaXR1cmUvb2NzLWhlYWx0aGV4cGVuZGl0dXJlLmh0bWwpLiBUaGUgdG9wIHR3byBsaW5lcyBvZiB0aGUgY29kZSBmb3IgdGhlIGZvbGxvd2luZyBwbG90cywgZmlsdGVyIHRoZSBkYXRhIHRvIG9ubHkgc3BlY2lmaWMgdmFsdWVzIG9mIGludGVyZXN0LiBUaGVuIHdlIGxheWVyIHdoYXQgaXMgY2FsbGVkIGEgaml0dGVyIG9uIHRvcCBvZiBhIGJveCBwbG90LiBBIGppdHRlciBpcyBlc3NlbnRpYWxseSBhIGRvdCBwbG90IGJ1dCB3aXRoIHNvbWUgdmFyaWF0aW9uIG9uIHRoZSBsb2NhdGlvbiBvZiB0aGUgcG9pbnRzIHNvIHRoYXQgdGhleSBkbyBub3QgbGluZSB1cCB2ZXJ0aWNhbGx5IHdoaWNoIGNhbiBtYWtlIHRoZSBpbmRpdmlkdWFsIHBvaW50cyBkaWZmaWN1bHQgdG8gc2VlLgoKTGV0J3MgbG9vayBhdCB0aGUgbmF0aW9uYWwgbWVhbiBCTUkgZXN0aW1hdGVzIGZvciBlYWNoIG9mIHRoZSB5ZWFyczoKYGBge3J9CkJNSV9sb25nICU+JSAKICBmaWx0ZXIoU2V4ID09ICJXb21lbiIsIAogICAgICAgICBZZWFyID09ICIxOTg1IiwgCiAgICAgICAgIFJlZ2lvbiAhPSAiTmF0aW9uYWwiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBSZWdpb24sIHkgPSBCTUkpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21faml0dGVyKHdpZHRoID0gLjMpIAojIHRoZSB3aWR0aCBkZXRlcm1pbmVzIGhvdyB3aWRlIHRoZSBwb2ludHMgYXJlIHBsb3R0ZWQKCkJNSV9sb25nICU+JSAKICBmaWx0ZXIoU2V4ID09ICJXb21lbiIsIAogICAgICAgICBZZWFyID09ICIyMDE3IiwgCiAgICAgICAgIFJlZ2lvbiAhPSAiTmF0aW9uYWwiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBSZWdpb24sIHkgPSBCTUkpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21faml0dGVyKHdpZHRoID0gLjMpCgpgYGAKCk5vdyBMZXQncyBsb29rIGF0IHRoZSBjaGFuZ2UgaW4gcnVyYWwgYW5kIHVyYmFuIG1lYW4gQk1JIGVzdGltYXRlczoKYGBge3J9CiN0aGlzIHRpbWUgd2Ugd2lsbCBhZGQgdGl0bGVzIGZvciBSdXJhbCBhbmQgVXJiYW4gdXNpbmcgZ2d0aXRsZSgpCkJNSV9sb25nICU+JSAKICBmaWx0ZXIoU2V4ID09ICJXb21lbiIsIAogICAgICAgICBZZWFyICVpbiUgYygiMTk4NSIsICIyMDE3IiksIAogICAgICAgICBSZWdpb24gPT0gIlJ1cmFsIikgJT4lCiAgIyBmaWx0ZXJpbmcgdGhpcyB3YXkgYWxsb3dzIHVzIHRvIGtlZXAgZGF0YSBmcm9tIGJvdGggeWVhcnMKICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gQk1JKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcih3aWR0aCA9IC4zKSArCiAgZ2d0aXRsZSgiUnVyYWwiKQoKQk1JX2xvbmcgJT4lIAogIGZpbHRlcihTZXggPT0gIldvbWVuIiwgCiAgICAgICAgIFllYXIgJWluJSBjKCIxOTg1IiwgIjIwMTciKSwgCiAgICAgICAgIFJlZ2lvbiA9PSAiVXJiYW4iKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gQk1JKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcih3aWR0aCA9IC4zKSArCiAgZ2d0aXRsZSgiVXJiYW4iKQoKYGBgCkxldCdzIHB1dCB0aGUgcGxvdHMgdG9nZXRoZXIgdG8gc2VlIGhvdyB0aGUgY2hhbmdlIG92ZXIgdGhlIHllYXJzIGRpZmZlcnMgYmV0d2VlbiB0aGUgcmVnaW9ucy4KV2Ugd2lsbCB1c2UgYWdhaW4gdXNlIGBmYWNldF93cmFwKClgIHRvIGRvIHRoaXM6CgpgYGB7cn0KCkJNSV9sb25nICU+JSAKICBmaWx0ZXIoU2V4ID09ICJXb21lbiIsIAogICAgICAgICBZZWFyICVpbiUgYygiMTk4NSIsICIyMDE3IiksIAogICAgICAgICBSZWdpb24gJWluJSBjKCJSdXJhbCIsICJVcmJhbiIpKSAlPiUKICAjIGZpbHRlcmluZyB0aGlzIHdheSBhbGxvd3MgdXMgdG8ga2VlcCBkYXRhIGZyb20gYm90aCB5ZWFycwogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBCTUkpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21faml0dGVyKHdpZHRoID0gLjMpICsKICBmYWNldF93cmFwKH4gUmVnaW9uKQoKIyB3ZSB3b3VsZCBhbHNvIGdldCBuYXRpb25hbCBkYXRhIHdpdGhvdXQgYFJlZ2lvbiAlaW4lIGMoIlJ1cmFsIiwgIlVyYmFuIikpYAoKYGBgCkluZGVlZCB0aGUgY2hhbmdlIGluIEJNSSBvdmVyIHRpbWUgbG9va3MgYmlnZ2VyIGluIHRoZSBydXJhbCBhcmVhcyEKCkhvdyBkbyB0aGUgZGlmZmVyZW50IGNvdW50cmllcyBjb21wYXJlPyAgT3IgaW4gb3RoZXIgd29yZHMgd2hhdCBkbyB0aGUgaW5kaXZpZHVhbCBkb3RzIHJlcHJlc2VudCBpbiBvdXIgYm94IHBsb3RzPwpXZSB3aWxsIHRha2UgYSBsb29rIHVzaW5nIGBnZW9tX2xhYmVsKClgOgoKYGBge3J9CgpCTUlfbG9uZyAlPiUgCiAgZmlsdGVyKFNleCA9PSAiV29tZW4iLCAKICAgICAgICAgWWVhciAlaW4lIGMoIjE5ODUiLCAiMjAxNyIpLCAKICAgICAgICAgUmVnaW9uID09ICJSdXJhbCIpICU+JQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBCTUkpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21faml0dGVyKHdpZHRoID0gLjMpICsKICBnZW9tX2xhYmVsKGFlcyhsYWJlbCA9IENvdW50cnkpKQoKYGBgCgpJZiB3ZSBpbmNsdWRlIGFsbCBjb3VudHJ5IG5hbWVzIHRoaXMgaXMgYSBiaXQgdG9vIG11Y2guLi4gc28gcGVyaGFwcyB3ZSBzaG91bGQgZm9jdXMgb24ganVzdCB0aGUgZXh0cmVtZSBCTUkgdmFsdWVzIHVzaW5nIGBmaWx0ZXIoKWAgZnVuY3Rpb24gb2YgdGhlYGRwbHlyYCBwYWNrYWdlLiBXZSB3aWxsIGFsc28gdXNlIHRoZSBgZ2dyZXBlbGAgcGFja2FnZSB0byBoYXZlIG91ciBsYWJlbHMgbm90IG92ZXJsYXAgZWFjaCBvdGhlci4KCgpgYGB7cn0KCkJNSV9sb25nICU+JSAKICBmaWx0ZXIoU2V4ID09ICJXb21lbiIsIAogICAgICAgICBZZWFyICVpbiUgYygiMTk4NSIsICIyMDE3IiksIAogICAgICAgICBSZWdpb24gPT0gIlJ1cmFsIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IEJNSSkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZ2VvbV9qaXR0ZXIoZGF0YT1CTUlfbG9uZyAlPiUgCiAgICAgICAgICAgICAgZmlsdGVyKFNleCA9PSAiV29tZW4iLCAKICAgICAgICAgICAgICAgICAgICAgWWVhciAlaW4lIGMoIjE5ODUiLCAiMjAxNyIpLCAKICAgICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJSdXJhbCIpICU+JQogICAgICAgICAgICAgIGZpbHRlcihCTUk+MzEgfCBCTUk8MTkgfCBDb3VudHJ5ID09ICJVbml0ZWQgU3RhdGVzIG9mIEFtZXJpY2EiKSwgCiAgICAgICAgICAgICAgYWVzKHggPVllYXIsIHkgPUJNSSksCiAgICAgICAgICAgICAgd2lkdGggPSAuMDIpICsKICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoZGF0YT1CTUlfbG9uZyAlPiUgCiAgICAgICAgICAgICAgZmlsdGVyKFNleCA9PSAiV29tZW4iLCAKICAgICAgICAgICAgICAgICAgICAgWWVhciAlaW4lIGMoIjE5ODUiLCAiMjAxNyIpLCAKICAgICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJSdXJhbCIpICU+JQogICAgICAgICAgICAgIGZpbHRlcihCTUk+MzEgfCBCTUk8MTkgfCBDb3VudHJ5ID09ICJVbml0ZWQgU3RhdGVzIG9mIEFtZXJpY2EiKSwgCiAgICAgICAgICAgICAgYWVzKHggPVllYXIsIHkgPUJNSSwgbGFiZWwgPSBDb3VudHJ5KSkKICAgICAgICAgICAgICAKICAgICAgICAgICAgICAKYGBgCgpBbmQgbGV0J3MgZmlsbCB0aGUgYm94IHBsb3RzIHdpdGggY29sb3IgYW5kIG91dGxpbmUgaW4gYmxhY2s6CmBgYHtyfQoKQk1JX2xvbmcgJT4lIAogIGZpbHRlcihTZXggPT0gIldvbWVuIiwgCiAgICAgICAgIFllYXIgJWluJSBjKCIxOTg1IiwgIjIwMTciKSwgCiAgICAgICAgIFJlZ2lvbiA9PSAiUnVyYWwiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gQk1JKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEsIGNvbG9yID0gImJsYWNrIiwgYWVzKGZpbGwgPSBZZWFyKSkgKwogIGdlb21faml0dGVyKGRhdGE9Qk1JX2xvbmcgJT4lIAogICAgICAgICAgICAgIGZpbHRlcihTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICAgIFllYXIgJWluJSBjKCIxOTg1IiwgIjIwMTciKSwgCiAgICAgICAgICAgICAgICAgICAgIFJlZ2lvbiA9PSAiUnVyYWwiKSAlPiUKICAgICAgICAgICAgICBzdWJzZXQoQk1JPjMxIHwgQk1JPDE5IHwgQ291bnRyeSA9PSAiVW5pdGVkIFN0YXRlcyBvZiBBbWVyaWNhIiksIAogICAgICAgICAgICAgIGFlcyh4ID1ZZWFyLCB5ID1CTUkpLAogICAgICAgICAgICAgIHdpZHRoID0gLjAyKSArCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGE9Qk1JX2xvbmcgJT4lIAogICAgICAgICAgICAgIGZpbHRlcihTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICAgIFllYXIgJWluJSBjKCIxOTg1IiwgIjIwMTciKSwgCiAgICAgICAgICAgICAgICAgICAgIFJlZ2lvbiA9PSAiUnVyYWwiKSAlPiUKICAgICAgICAgICAgICBzdWJzZXQoQk1JPjMxIHwgQk1JPDE5IHwgQ291bnRyeSA9PSAiVW5pdGVkIFN0YXRlcyBvZiBBbWVyaWNhIiksIAogICAgICAgICAgICAgIGFlcyh4ID1ZZWFyLCB5ID1CTUksIGxhYmVsID0gQ291bnRyeSkpCgpgYGAKCgojIyMgT3ZlcmFsbCBkaWZmZXJlbmNlcwoKTGV0J3MgdGFrZSBhIGxvb2sgYXQgYWxsIHRoZSBkYXRhIHRvZ2V0aGVyOgpgYGB7cn0KZ2dwbG90KEJNSV9sb25nLCBhZXMoeCA9IFllYXIsIHkgPSBCTUksIGNvbCA9IFJlZ2lvbikpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BLCBjb2xvciA9ICJibGFjayIgLCBhZXMoZmlsbCA9IFJlZ2lvbikpICsgCiAgZmFjZXRfZ3JpZCh+IFNleCkgICAKYGBgCgpUaGF0J3MgdXNlZnVsLCBidXQgbGV0J3MgbG9vayBhdCB0aGUgaW5kaXZpZHVhbCBwb2ludHMgYW5kIGluY2x1ZGUgb3VyIGNvdW50cnkgbGFiZWxzLCB0byBkbyBzbyBsZXRzIGNoYW5nZSBvdXIgVW5pdGVkIFN0YXRlcyBvZiBBbWVyaWNhIGxhYmVsIHRvIFVTQToKYGBge3J9CkJNSV9sb25nJENvdW50cnkgPC1CTUlfbG9uZyRDb3VudHJ5ICU+JQogIHN0cl9yZXBsYWNlKCBwYXR0ZXJuID0gIlVuaXRlZCBTdGF0ZXMgb2YgQW1lcmljYSIsIHJlcGxhY2VtZW50ID0gIlVTQSIpCgoKZ2dwbG90KEJNSV9sb25nLCBhZXMoeCA9IFllYXIsIHkgPSBCTUksIGNvbCA9IFllYXIpKSArIAogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEsIGNvbG9yID0gImJsYWNrIiAsIGFlcyhmaWxsID0gWWVhcikpICsgCiAgZmFjZXRfZ3JpZCh+IFNleCArIFJlZ2lvbikgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MzAsIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvciA9ICJyZWQiLCBzaXplID0xKSArIAogICMgVGhpcyB3aWxsIGFkZCBhIGhvcml6b250YWwgZGFzaGVkIGxpbmUgdG8gaW5kaWNhdGUgdGhlIG9iZXNpdHkgQk1JIHRocmVzaG9sZAogIGdlb21faml0dGVyKGRhdGE9c3Vic2V0KEJNSV9sb25nKSwgCiAgICAgICAgICAgICAgYWVzKHggPVllYXIsIHkgPUJNSSksIAogICAgICAgICAgICAgIHdpZHRoID0gLjIsIHNpemUgPTIsIHNoYXBlID0yMSwgY29sb3IgPSAiYmxhY2siLCBmaWxsID0gImdyYXkiKSArIAogICMgVGhpcyB3aWxsIGFkZCB0aGUgaW5kaXZpZHVhbCBjb3VudHJ5IGRhdGEgcG9pbnRzCiAgIyBUaGUgc2hhcGUgMjEgYWxsb3dzIGZvciBhIGRpZmZlcmVudCBmaWxsIGFuZCBvdXRsaW5lIGNvbG9yCiAgIyBUaGUgd2lkdGggZGV0ZXJtaW5lcyBob3cgd2lkZSB0aGUgaml0dGVyIHBvaW50cyBhcmUgcGxvdHRlZAogIGdlb21faml0dGVyKGRhdGE9c3Vic2V0KEJNSV9sb25nLCBDb3VudHJ5ID09ICJVU0EiKSwgCiAgICAgICAgICAgICAgYWVzKHggPVllYXIsIHkgPUJNSSksIAogICAgICAgICAgICAgIHdpZHRoID0gLjAyLCBzaXplID0xMiwgc2hhcGUgPTIxLCBjb2xvciA9ICJibGFjayIsIGZpbGwgPSAiZ3JheSIpICsgCiAgIyBUaGlzIHdpbGwgYWRkIHBvaW50cyB0aGF0IGFyZSBsYXJnZXIgZm9yIHRoZSBVU0EgZGF0YQogIGdlb21fdGV4dChkYXRhPXN1YnNldChCTUlfbG9uZywgIENvdW50cnkgPT0gIlVTQSIpLCAKICAgICAgICAgICAgYWVzKHggPVllYXIsIHkgPUJNSSxsYWJlbD1Db3VudHJ5KSwgCiAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIikgKyAKICAjIFRoaXMgd2lsbCBhZGQgVVNBIGxhYmVscyB0byB0aGUgVVNBIHBvaW50cwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgCiAgIyBUaGlzIGlzIHVzZWZ1bCBmb3IgcmVtb3ZpbmcgdGhlIGxlZ2VuZAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSxhbmdsZSA9IDMwKSwgCiAgICAgICAgIyB0aGlzIGNoYW5nZXMgdGhlIHNpemUgYW5kIGFuZ2xlIG9mIHRoZSB4IGF4aXMgcG9pbnQgbGFiZWxzIAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksIAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0xNSksIAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0xNSksIAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpKSArCiAgIyBUaGlzIGNoYW5nZXMgdGhlIHNpemUgb2YgeCBheGlzIGxhYmVscyBmb3IgdGhlIGZhY2V0IAogICAgICAgIGdndGl0bGUoICJEaWZmZXJlbmNlcyBpbiBCTUkgT3ZlciBUaW1lIGFuZCBBY3Jvc3MgUmVnaW9uIFR5cGUgYW5kIEdlbmRlciIpIAogICMgQWRkIGEgIHBsb3QgdGl0bGUKICAgCgoKYGBgCgpIZXJlIHdlIGNhbiBzZWUgdGhhdCBvdmVyYWxsIEJNSSBhcHBlYXJzIHRvIGJlIGluY3JlYXNpbmcgZ2xvYmFsbHkgb3ZlciB0aW1lLiBBZGRpdGlvbmFsbHkgd2UgY2FuIHNlZSB0aGF0IHRoaXMgaXMgb2NjdXJyaW5nIG5vdCBqdXN0IGluIHVyYmFuIGFyZWFzLCBidXQgYWxzbyBpbiBydXJhbCBhcmVhcy4gVGhlIFVTIGlzIGNvbnNpc3RlbnRseSBhYm92ZSB0aGUgbWVkaWFuIGluIGFsbCBzdHJhdGEgb2YgdGhlIGRhdGEuIEluIGdlbmVyYWwsIHRoZSBmZW1hbGUgZGF0YSBzaG93cyBoaWdoZXIgQk1JIHZhbHVlcyB0aGFuIHRoZSBtYWxlIGRhdGEuIFRoZSBydXJhbCBVU0EgQk1JIGFwcGVhcnMgdG8gYmUgaGlnaGVyIHRoYW4gdGhlIHVyYmFuIEJNSSBmb3IgYm90aCBtZW4gYW5kIHdvbWVuLiBNYW55IGNvdW50cmllcyBoYXZlIGF2ZXJhZ2UgQk1JIGVzdGltYXRlcyBhYm92ZSB0aGUgb2Jlc2l0eSB0aHJlc2hvbGQgb2YgMzAuIFRodXMgaXQgYXBwZWFycyB0aGF0IGVkdWNhdGlvbiBhbmQgb3V0cmVhY2ggcHJvZ3JhbXMgZm9yIHdlaWdodCBtYW5hZ2VtZW50IHNob3VsZCBmb2N1cyBvbiBib3RoIHJ1cmFsIGFuZCB1cmJhbiBhcmVhcyBhbmQgYm90aCBnZW5kZXJzLiBFZHVjYXRpb24gYW5kIGFzc2lzdGFuY2UgZm9yIHdvbWVuIG1heSBiZSBlc3BlY2lhbGx5IGhlbHBmdWwuIAoKIyMjIERpZmZlcmVuY2VzIGluIHJhdGUgb2YgY2hhbmdlIGluIEJNSQoKSG93IGRvZXMgdGhlIHJhdGUgb2YgY2hhbmdlIGluIEJNSSBkaWZmZXIgYmV0d2VlbiBncm91cHM/IFdoaWNoIGdyb3VwIG1pZ2h0IGVzcGVjaWFsbHkgbmVlZCBhdHRlbnRpb24/CgpGaXJzdCBsZXQncyBjYWxjdWxhdGUgdGhlIGRpZmZlcmVuY2VzIGluIEJNSSBmcm9tIDIwMTcgYW5kIDE5ODUgYW5kIGFkZCB0aGlzIHRvIG91ciBCTUlfbG9uZyBkYXRhIG9iamVjdDoKYGBge3J9CgpCTUlfbnVtZXJpYyRSdXJhbF9kaWZmZXJlbmNlIDwtIAogICAgIEJNSV9udW1lcmljJFJ1cmFsX0JNSV8yMDE3IC0gQk1JX251bWVyaWMkUnVyYWxfQk1JXzE5ODUKCkJNSV9udW1lcmljJFVyYmFuX2RpZmZlcmVuY2UgPC0gCiAgICAgQk1JX251bWVyaWMkVXJiYW5fQk1JXzIwMTcgLSBCTUlfbnVtZXJpYyRVcmJhbl9CTUlfMTk4NQoKQk1JX251bWVyaWMkTmF0aW9uYWxfZGlmZmVyZW5jZSA8LSAKICAgICBCTUlfbnVtZXJpYyROYXRpb25hbF9CTUlfMjAxNyAtIEJNSV9udW1lcmljJE5hdGlvbmFsX0JNSV8xOTg1CgpCTUlfZGlmZl9sb25nIDwtIEJNSV9udW1lcmljICU+JSAKICBzZWxlY3QoQ291bnRyeTogTmF0aW9uYWxfZGlmZmVyZW5jZSkgJT4lIApnYXRoZXIoa2V5ID0gVHlwZSwgdmFsdWUgPSBEaWZmZXJlbmNlICwgUnVyYWxfZGlmZmVyZW5jZTpOYXRpb25hbF9kaWZmZXJlbmNlKQoKaGVhZChCTUlfZGlmZl9sb25nKQpgYGAKCkxldCdzIHJlcGxhY2UgIlVuaXRlZCBzdGF0ZXMgb2YgQW1lcmljYSIgd2l0aCAiVVNBIiBhbmQgbWFrZSBhIHBsb3Qgd2l0aCB0aGlzIGRhdGEgdG8gY29tcGFyZSB0aGUgY2hhbmdlIGluIEJNSToKCmBgYHtyfQoKQk1JX2RpZmZfbG9uZyRDb3VudHJ5IDwtQk1JX2RpZmZfbG9uZyRDb3VudHJ5ICU+JQogIHN0cl9yZXBsYWNlKCBwYXR0ZXJuID0gIlVuaXRlZCBTdGF0ZXMgb2YgQW1lcmljYSIsIHJlcGxhY2VtZW50ID0gIlVTQSIpCgoKZ2dwbG90KEJNSV9kaWZmX2xvbmcsIGFlcyh4ID0gVHlwZSwgeSA9IERpZmZlcmVuY2UsIGNvbCA9IFR5cGUpKSArIAogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEsIGNvbG9yID0gImJsYWNrIiAsIGFlcyhmaWxsID0gVHlwZSkpICsgCiAgZmFjZXRfZ3JpZCh+IFNleCkgKwogIGdlb21faml0dGVyKGRhdGE9c3Vic2V0KEJNSV9kaWZmX2xvbmcpLCAKICAgICAgICAgICAgICBhZXMoeCA9VHlwZSwgeSA9RGlmZmVyZW5jZSksIAogICAgICAgICAgICAgIHdpZHRoID0gLjIsIHNpemUgPTIsIHNoYXBlID0yMSwgY29sb3IgPSAiYmxhY2siLCBmaWxsID0gImdyYXkiKSArIAogICMgVGhpcyB3aWxsIGFkZCB0aGUgaW5kaXZpZHVhbCBjb3VudHJ5IGRhdGEgcG9pbnRzCiAgIyBUaGUgc2hhcGUgMjEgYWxsb3dzIGZvciBhIGRpZmZlcmVudCBmaWxsIGFuZCBvdXRsaW5lIGNvbG9yCiAgIyBUaGUgd2lkdGggZGV0ZXJtaW5lcyBob3cgd2lkZSB0aGUgaml0dGVyIHBvaW50cyBhcmUgcGxvdHRlZAogIGdlb21faml0dGVyKGRhdGE9c3Vic2V0KEJNSV9kaWZmX2xvbmcsIENvdW50cnkgPT0gIlVTQSIpLCAKICAgICAgICAgICAgICBhZXMoeCA9VHlwZSwgeSA9RGlmZmVyZW5jZSksIAogICAgICAgICAgICAgIHdpZHRoID0gLjAyLCBzaXplID0xMiwgc2hhcGUgPTIxLCBjb2xvciA9ICJibGFjayIsIGZpbGwgPSAiZ3JheSIpICsgCiAgIyBUaGlzIHdpbGwgYWRkIHBvaW50cyB0aGF0IGFyZSBsYXJnZXIgZm9yIHRoZSBVU0EgZGF0YQogIGdlb21fdGV4dChkYXRhPXN1YnNldChCTUlfZGlmZl9sb25nLCAgQ291bnRyeSA9PSAiVVNBIiksIAogICAgICAgICAgICBhZXMoeCA9VHlwZSwgeSA9RGlmZmVyZW5jZSxsYWJlbD1Db3VudHJ5KSwgY29sb3IgPSAiYmxhY2siKSArIAogICMgVGhpcyB3aWxsIGFkZCBVU0EgbGFiZWxzIHRvIHRoZSBVU0EgcG9pbnRzCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAKICAjIFRoaXMgaXMgdXNlZnVsIGZvciByZW1vdmluZyB0aGUgbGVnZW5kCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LGFuZ2xlID0gMzApLCAKICAgICAgICAjIHRoaXMgY2hhbmdlcyB0aGUgc2l6ZSBhbmQgYW5nbGUgb2YgdGhlIHggYXhpcyBwb2ludCBsYWJlbHMgCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwgCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPTE1KSwgCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPTE1KSwgCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpICsKICAgICAgICAjIHRoaXMgY2hhbmdlcyB0aGUgc2l6ZSBvZiB4IGF4aXMgbGFiZWxzIGZvciB0aGUgZmFjZXQKICAgICAgICBnZ3RpdGxlKCAiQ2hhbmdlIGluIEJNSSBPdmVyIFRpbWUgYW5kIEFjcm9zcyBSZWdpb24gVHlwZSBhbmQgR2VuZGVyIikKICAgICAgICAjIEFkZCBhIHBsb3QgdGl0bGUgIAoKCgpgYGAKCldlIGNhbiBub3cgc2VlIHRoYXQgdGhlIHJhdGUgb2YgY2hhbmdlIGZyb20gMTk4NSB0byAyMDE3IGFwcGVhcnMgdG8gYmUgbGFyZ2VyIGluIHRoZSB3b21lbiBjb21wYXJlZCB0byB0aGUgbWVuIGluIGFsbCByZWdpb25zLiBUaGUgZ3JvdXAgd2l0aCB0aGUgbGFyZ2VzdCBpbmNyZWFzZSBpbiB0aGUgVVNBIGlzIHRoZSB3b21lbiBsaXZpbmcgaW4gcnVyYWwgYXJlYXMuCgpMZXQncyBjaGVjayB0aGUgZGlmZmVyZW5jZSB3aXRoIHNvbWUgc3RhdGlzdGljYWwgdGVzdHM6CgpgYGB7cn0KI2ZpcnN0IGxldHMgbG9vayBhdCB0aGUgbm9ybWFsaXR5IG9mIHRoZSBkaWZmZXJlbmNlIGluIEJNSQpCTUlfZGlmZl9sb25nICU+JQogIGdncGxvdChhZXMoeD1EaWZmZXJlbmNlKSkgKwogIGdlb21faGlzdG9ncmFtKCkgKwogIGZhY2V0X3dyYXAofiBTZXggKyBUeXBlKQojIGludGVyZXN0aW5nLi4udGhlIHNwcmVhZCBvZiBkaWZmZXJlbmNlIGlzIG11Y2ggYnJvYWRlciBmb3Igd29tZW4gdGhhbiBmb3IgbWVuIAojIHNvbWUgd29tZW4gaW4gc29tZSBjb3VudHJpZXMgZXNwZWNpYWxseSBuZWVkIGhlbHAgd2l0aCBvYmVzaXR5CiMgd2hpbGUgb3RoZXIgY291bnRyaWVzIGFyZSBhY3R1YWxseSBzaG93aW5nIGEgbG9zcyBvZiBCTUkKIyB0aGVzZSBjb3VudHJpZXMgYXJlIHRoZSBwb2ludHMgb24gb3VyIHByZXZpb3VzIHBsb3Qgd2l0aCBhIGRpZmZlcmVuY2UgYmVsb3cgMAoKI0xldCdzIHNlZSB3aG86CkJNSV9kaWZmX2xvbmcgJT4lIAogIGFycmFuZ2UoRGlmZmVyZW5jZSkKCiMgSW4gZ2VuZXJhbCwgcGVvcGxlIGFwcGVhciB0byBoYXZlIGxvc3Qgd2VpZ2h0IGluIEdyZWVjZQoKIyBMZXQncyBsb29rIGF0IFEtUSBwbG90czoKQk1JX2RpZmZfbG9uZyAlPiUKICBnZ3Bsb3QoYWVzKHNhbXBsZSA9RGlmZmVyZW5jZSkpICsKICBzdGF0X3FxKCkgKyAjIHRvIGFkZCB0aGUgbGluZSB3ZSBuZWVkIHRvIGFsc28gaW5jbHVkZSBzdGF0X3FxX2xpbmUoKQogIHN0YXRfcXFfbGluZSgpICsKICBmYWNldF93cmFwKH4gU2V4ICsgVHlwZSkKCiMgb2sgc28gc29tZSBvZiB0aGUgZGF0YSBmb3IgTWVuIGxvb2tzIGZhaXJseSBub3JtYWwgYnV0IG5vdCBhcyBtdWNoIGZvciBXb21lbgoKIyBOb3cgd2Ugd2lsbCBjaGVjayB0aGUgdmFyaWFuY2UKCm1vb2QudGVzdChwdWxsKGZpbHRlcihCTUlfZGlmZl9sb25nLCAKICAgICAgICAgICAgICAgICAgICAgIFNleCA9PSAiV29tZW4iLCAKICAgICAgICAgICAgICAgICAgICAgIFR5cGUgPT0gIlJ1cmFsX2RpZmZlcmVuY2UiKSwgRGlmZmVyZW5jZSksIAogICAgICAgICAgcHVsbChmaWx0ZXIoQk1JX2RpZmZfbG9uZywgCiAgICAgICAgICAgICAgICAgICAgICBTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICAgICBUeXBlID09ICJVcmJhbl9kaWZmZXJlbmNlIiksIERpZmZlcmVuY2UpKQojcmVqZWN0IHRoZSBudWxsIC0gY29uY2x1ZGUgdGhhdCB2YXJpYW5jZSBpcyBub3QgZXF1YWwKCm1vb2QudGVzdChwdWxsKGZpbHRlcihCTUlfZGlmZl9sb25nLCAKICAgICAgICAgICAgICAgICAgICAgIFNleCA9PSAiTWVuIiwgCiAgICAgICAgICAgICAgICAgICAgICBUeXBlID09ICJSdXJhbF9kaWZmZXJlbmNlIiksIERpZmZlcmVuY2UpLCAKICAgICAgICAgIHB1bGwoZmlsdGVyKEJNSV9kaWZmX2xvbmcsIAogICAgICAgICAgICAgICAgICAgICAgU2V4ID09ICJNZW4iLCAKICAgICAgICAgICAgICAgICAgICAgIFR5cGUgPT0gIlVyYmFuX2RpZmZlcmVuY2UiKSwgRGlmZmVyZW5jZSkpCiNhY2NlcHQgdGhlIG51bGwgLSBjb25jbHVkZSB0aGF0IHZhcmlhbmNlIGlzIGVxdWFsCgptb29kLnRlc3QocHVsbChmaWx0ZXIoQk1JX2RpZmZfbG9uZywgCiAgICAgICAgICAgICAgICAgICAgICBTZXggPT0gIldvbWVuIiwgCiAgICAgICAgICAgICAgICAgICAgICBUeXBlID09ICJSdXJhbF9kaWZmZXJlbmNlIiksIERpZmZlcmVuY2UpLCAKICAgICAgICAgIHB1bGwoZmlsdGVyKEJNSV9kaWZmX2xvbmcsIAogICAgICAgICAgICAgICAgICAgICAgU2V4ID09ICJNZW4iLCAKICAgICAgICAgICAgICAgICAgICAgIFR5cGUgPT0gIlJ1cmFsX2RpZmZlcmVuY2UiKSwgRGlmZmVyZW5jZSkpCiNyZWplY3QgdGhlIG51bGwgLSBjb25jbHVkZSB0aGF0IHZhcmlhbmNlIGlzIG5vdCBlcXVhbAoKCiMgbGV0J3MgY29tcGFyZSB0aGUgZ3JvdXBzCiMgdGhpcyBpcyBhZ2FpbiBzdGlsbCBwYWlyZWQgZGF0YQojIHRoaXMgaXMgYmVjYXVzZSBlYWNoIHZhbHVlIG9mICJSdXJhbF9kaWZmZXJlbmNlIiBhbmQgIlVyYmFuX2RpZmZlcmVuY2UiIGNvcnJlc3BvbmQgdG8gdGhlIHNhbWUgY291bnRyeQoKa3MudGVzdChwdWxsKGZpbHRlcihCTUlfZGlmZl9sb25nLCAKICAgICAgICAgICAgICAgICAgICBTZXggPT0gIldvbWVuIiwgIAogICAgICAgICAgICAgICAgICAgIFR5cGUgPT0gIlJ1cmFsX2RpZmZlcmVuY2UiKSwgRGlmZmVyZW5jZSksIAogICAgICAgIHB1bGwoZmlsdGVyKEJNSV9kaWZmX2xvbmcsCiAgICAgICAgICAgICAgICAgICAgU2V4ID09ICJXb21lbiIsICAKICAgICAgICAgICAgICAgICAgICBUeXBlID09ICJVcmJhbl9kaWZmZXJlbmNlIiksIERpZmZlcmVuY2UpLAogICAgICAgIHBhaXJlZCA9IFRSVUUpIAoKa3MudGVzdChwdWxsKGZpbHRlcihCTUlfZGlmZl9sb25nLAogICAgICAgICAgICAgICAgICAgIFNleCA9PSAiTWVuIiwKICAgICAgICAgICAgICAgICAgICBUeXBlID09ICJSdXJhbF9kaWZmZXJlbmNlIiksIERpZmZlcmVuY2UpLCAKICAgICAgICBwdWxsKGZpbHRlcihCTUlfZGlmZl9sb25nLAogICAgICAgICAgICAgICAgICAgIFNleCA9PSAiTWVuIiwgCiAgICAgICAgICAgICAgICAgICAgVHlwZSA9PSAiVXJiYW5fZGlmZmVyZW5jZSIpLCBEaWZmZXJlbmNlKSwKICAgICAgICBwYWlyZWQgPSBUUlVFKQoKa3MudGVzdChwdWxsKGZpbHRlcihCTUlfZGlmZl9sb25nLAogICAgICAgICAgICAgICAgICAgIFNleCA9PSAiTWVuIiwgCiAgICAgICAgICAgICAgICAgICAgVHlwZSA9PSAiUnVyYWxfZGlmZmVyZW5jZSIpLCBEaWZmZXJlbmNlKSwgCiAgICAgICAgcHVsbChmaWx0ZXIoQk1JX2RpZmZfbG9uZywgCiAgICAgICAgICAgICAgICAgICAgU2V4ID09ICJXb21lbiIsICAKICAgICAgICAgICAgICAgICAgICBUeXBlID09ICJSdXJhbF9kaWZmZXJlbmNlIiksIERpZmZlcmVuY2UpLAogICAgICAgIHBhaXJlZCA9IFRSVUUpCgpgYGAKTm93IHdlIGhhdmUgcGVyZm9ybWVkIHNldmVuIGNvbXBhcmlzb25zICg0IGVhcmxpZXIpIHNvIHdlIHNob3VsZCBhcHBseSBvdXIgbXVsdGlwbGUgdGVzdGluZyBjb3JyZWN0aW9uCmBgYHtyfQouMDUvNwoKYGBgCgpXZSBzZWUgdGhhdCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gdGhlIGNoYW5nZSBpbiBCTUkgUnVyYWwgY29tbXVuaXRpZXMgYmV0d2VlbiBtZW4gYW5kIHdvbWVuLiBUaGlzIGNoYW5nZSBpcyBsYXJnZXIgZm9yIHdvbWVuLgoKSW1wb3J0YW50bHktIHdlIG5vdGljZWQgdGhhdCBpdCBhcHBlYXJzIHRvIGJlIHNwZWNpZmljIGNvdW50cmllcyB3aGVyZSBCTUkgc2hvd3MgYSBwYXJ0aWN1bGFyIGluY3JlYXNlIGVzcGVjaWFsbHkgZm9yIHdvbWVuLiBXaGljaCBjb3VudHJpZXMgYXJlIHRob3NlPyBob3cgZG9lcyB0aGF0IGNvbXBhcmUgd2l0aCB0aGUgVVM/IENsZWFybHkgdGhlIFVTIGlzIGFtb25nIHRoZSBjb3VudHJpZXMgd2l0aCB0aGUgaGlnaGVzdCBkaWZmZXJlbmNlcy4gCgpgYGB7cn0KQk1JX2RpZmZfbG9uZyAlPiUgCiAgZmlsdGVyKENvdW50cnkgPT0gIlVTQSIpCgpgYGAKCkluIHRoZSBVUywgZm9jdXMgc2hvdWxkIGJlIHBsYWNlZCBvbiA8Yj4gYm90aCB1cmJhbiBhbmQgcnVyYWwgPC9iPiB3b21lbiB0byBpbXByb3ZlIHRoaXMgcHVibGljIGhlYWx0aCBpc3N1ZS4gCgpIZXJlIHdlIGNhbiBzZWUgdGhlIGNvdW50cmllcyBoYXZlIHRoZSBsYXJnZXN0IGRpZmZlcmVuY2VzIGluIEJNSSBmcm9tIDE5ODUtMjAxNzoKCmBgYHtyfQpCTUlfZGlmZl9sb25nICU+JQogIGZpbHRlcihEaWZmZXJlbmNlPjQuOSkgJT4lCiAgYXJyYW5nZSgtRGlmZmVyZW5jZSkKI2hlcmUgd2Ugc29ydGVkIGJ5IHRoZSBoaWdoZXN0IHRvIGxvd2VzdCB2YWx1ZXMgb2YgQk1JIERpZmZlcmVuY2UKYGBgCgoKSG93ZXZlciBpdCBpcyBpbXBvcnRhbnQgdG8gc2VlIHdoYXQgdGhlIG1lYW4gQk1JIHZhbHVlcyBhcmUgd2VyZSBmb3IgdGhlc2UgY291bnRyaWVzIGluIDIwMTcuIApJdCBjb3VsZCBiZSB0aGF0IHRoZSBhdmVyYWdlIHdhcyB1bmRlcndlaWdodCBpbiAxOTg1Li4uIGxldCdzIHRha2UgYSBsb29rLgoKYGBge3J9CkJNSV9sb25nICU+JSAKICBmaWx0ZXIoQ291bnRyeSAlaW4lIHB1bGwoZmlsdGVyKEJNSV9kaWZmX2xvbmcsIERpZmZlcmVuY2U+NC45KSwgQ291bnRyeSksIAogICAgICAgICAgICAgICAgICAgIFNleCAlaW4lIHB1bGwoZmlsdGVyKEJNSV9kaWZmX2xvbmcsIERpZmZlcmVuY2U+NC45KSwgU2V4KSwKICAgICAgICAgICAgICAgICAgICBZZWFyID09IjIwMTciKSAlPiUKICBhcnJhbmdlKC1CTUkpCgojSGVyZSBpcyB0aGUgZGF0YSBqdXN0IGZvciB0aGUgY2hhbmdlcyBpbiBCTUkgaW4gRWd5cHQKZmlsdGVyKEJNSV9kaWZmX2xvbmcsIENvdW50cnkgPT0gIkVneXB0IikgJT4lIAogIGFycmFuZ2UoLURpZmZlcmVuY2UpCgpgYGAKVGh1cyBydXJhbCB3b21lbiBpbiBFZ3lwdCBoYWQgdGhlIGdyZWF0ZXN0IGluY3JlYXNlIGluIEJNSSBmcm9tIDE5ODUgdG8gMjAxNyBpbiB0aGlzIGRhdGEgKDUuOSkgYW5kIHRoZSBhdmVyYWdlIEJNSSBpcyBub3cgb3ZlciB0aGUgb2Jlc2l0eSB0aHJlc2hvbGQgb2YgMzAuCgpUaGUgZGF0YSBzdWdnZXN0cyB0aGF0IHJ1cmFsIHdvbWVuIGluIEVneXB0IGFuZCBvdGhlciBjb3VudHJpZXMgbWF5IGVzcGVjaWFsbHkgYmVuZWZpdCBmcm9tIGRpZXRhcnkgcmVzb3VyY2VzIGFuZCBvdXIgaW50ZXJ2ZW50aW9ucyBhbmQgcHJvZ3JhbXMgdG8gYXNzaXN0IHdpdGggd2VpZ2h0IG1hbmFnZW1lbnQuCgpOb3cgbGV0J3MgbWFrZSBhIHBsb3QgdGhhdCBzdW1tYXJpemVzIG91ciBmaW5kaW5ncy4gVG8gZG8gdGhpcyB3ZSB3aWxsIHNpbXBsaWZ5IHRoZSBvdGhlciBwbG90cyB3ZSBtYWRlIGFuZCB0aGVuIGNvbWJpbmUgdGhlbSB0b2dldGhlci4KCmBgYHtyfQoKIyBzaW1wbGlmaWVkIG5hdGlvbmFsIG1lYW5zIHBsb3QKTWVhbnNfcGxvdDwtQk1JX2xvbmcgJT4lIAogIGZpbHRlcihTZXggJWluJSBjKCJNZW4iLCAiV29tZW4iKSwgCiAgICAgICAgIFllYXIgJWluJSBjKCIxOTg1IiwgIjIwMTciKSwgCiAgICAgICAgIFJlZ2lvbiA9PSAiTmF0aW9uYWwiKSAlPiUKZ2dwbG90KGFlcyh4ID0gU2V4LCB5ID0gQk1JKSkgKyAKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BLCBjb2xvciA9ICJibGFjayIgLCBhZXMoZmlsbCA9IFNleCkpICsgCiBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiZG9kZ2VyYmx1ZSIsICJvcmNoaWQyIikpICsKICBmYWNldF9ncmlkKH4gWWVhcikgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MzAsIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvciA9ICJyZWQiLCBzaXplID0xKSArIAogIGdlb21faml0dGVyKGRhdGE9Qk1JX2xvbmcgJT4lCiAgICAgICAgICAgICAgICBmaWx0ZXIoU2V4ICVpbiUgYygiTWVuIiwgIldvbWVuIiksIAogICAgICAgICAgICAgICAgICAgICAgIFllYXIgJWluJSBjKCIxOTg1IiwgIjIwMTciKSwgCiAgICAgICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJOYXRpb25hbCIpLAogICAgICAgICAgICAgICAgYWVzKHggPVNleCwgeSA9Qk1JKSwgCiAgICAgICAgICAgICAgICB3aWR0aCA9IC4yLCBzaXplID0yLCBzaGFwZSA9MjEsIAogICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBmaWxsID0gImdyYXkiKSArCiAgZ2VvbV9qaXR0ZXIoZGF0YT1zdWJzZXQoQk1JX2xvbmcgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoU2V4ICVpbiUgYygiTWVuIiwgIldvbWVuIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFllYXIgJWluJSBjKCIxOTg1IiwgIjIwMTciKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJOYXRpb25hbCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENvdW50cnkgPT0gIlVTQSIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPVNleCwgeSA9Qk1JKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGggPSAuMDIsIHNpemUgPTEyLCBzaGFwZSA9MjEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgZmlsbCA9ICJncmF5IikgKyAKICAjIFRoaXMgd2lsbCBhZGQgcG9pbnRzIHRoYXQgYXJlIGxhcmdlciBmb3IgdGhlIFVTQSBkYXRhCiAgZ2VvbV90ZXh0KGRhdGE9c3Vic2V0KEJNSV9sb25nJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKFNleCAlaW4lIGMoIk1lbiIsICJXb21lbiIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWWVhciAlaW4lIGMoIjE5ODUiLCAiMjAxNyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUmVnaW9uID09ICJOYXRpb25hbCIsIENvdW50cnkgPT0gIlVTQSIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9U2V4LCB5ID1CTUksbGFiZWw9Q291bnRyeSksIAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIikgKyAKICAjIFRoaXMgd2lsbCBhZGQgVVNBIGxhYmVscyB0byB0aGUgVVNBIHBvaW50cwogIHRoZW1lX2xpbmVkcmF3KCkgKwogICMgVGhpcyB3aWxsIG1ha2UgdGhlYmFja2dyb3VuZCBvZiB0aGUgcGxvdCB3aGl0ZSBhbmQgdGhlIGZhY2V0IGxhYmVscyBibGFjawogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgCiAgIyBUaGlzIGlzIHVzZWZ1bCBmb3IgcmVtb3ZpbmcgdGhlIGxlZ2VuZAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSxhbmdsZSA9IDMwLCB2anVzdCA9IDAuNSksIAogICAgICAgICMgdGhpcyBjaGFuZ2VzIHRoZSBzaXplIGFuZCBhbmdsZSBvZiB0aGUgeCBheGlzIHBvaW50IGxhYmVscyAKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLCAKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9MTUpLCAKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9MTUpLCAKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSkKICAgCiNTaW1wbGlmaWVkIGRpZmZlcmVuY2UgcGxvdCAKQk1JX2RpZmZfbG9uZyRUeXBlIDwtQk1JX2RpZmZfbG9uZyRUeXBlICU+JQogIHN0cl9yZXBsYWNlKCBwYXR0ZXJuID0gIl9kaWZmZXJlbmNlIiwgcmVwbGFjZW1lbnQgPSAiIikKCkRpZmZfcGxvdDwtQk1JX2RpZmZfbG9uZyAlPiUgCiAgZmlsdGVyKFNleCAlaW4lIGMoIk1lbiIsICJXb21lbiIpLCAKICAgICAgICAgVHlwZSAhPSAiTmF0aW9uYWwiKSAlPiUKZ2dwbG90KCBhZXMoeCA9IFR5cGUsIHkgPSBEaWZmZXJlbmNlLCBjb2wgPSBUeXBlKSkgKyAKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BLCBjb2xvciA9ICJibGFjayIgLCBhZXMoZmlsbCA9IFNleCkpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImRvZGdlcmJsdWUiLCAib3JjaGlkMiIpKSArCiAgZmFjZXRfZ3JpZCh+IFNleCkgKwogIGdlb21faml0dGVyKGRhdGE9Qk1JX2RpZmZfbG9uZyAlPiUgCiAgICBmaWx0ZXIoU2V4ICVpbiUgYygiTWVuIiwgIldvbWVuIiksIAogICAgICAgICAgIFR5cGUgIT0gIk5hdGlvbmFsIiksIAogICAgYWVzKHggPVR5cGUsIHkgPURpZmZlcmVuY2UpLCAKICAgIHdpZHRoID0gLjIsIHNpemUgPTIsIHNoYXBlID0yMSwgCiAgICBjb2xvciA9ICJibGFjayIsIGZpbGwgPSAiZ3JheSIpICsgCiAgZ2VvbV9qaXR0ZXIoZGF0YT1zdWJzZXQoQk1JX2RpZmZfbG9uZyAlPiUgCiAgICBmaWx0ZXIoU2V4ICVpbiUgYygiTWVuIiwgIldvbWVuIiksIAogICAgICAgICAgIFR5cGUgIT0gIk5hdGlvbmFsIiwgCiAgICAgICAgICAgQ291bnRyeSA9PSAiVVNBIikpLCAKICAgIGFlcyh4ID1UeXBlLCB5ID1EaWZmZXJlbmNlKSwgCiAgICB3aWR0aCA9IC4wMiwgc2l6ZSA9MTIsIHNoYXBlID0yMSwgCiAgICBjb2xvciA9ICJibGFjayIsIGZpbGwgPSAiZ3JheSIpICsgCiAgIyBUaGlzIHdpbGwgYWRkIHBvaW50cyB0aGF0IGFyZSBsYXJnZXIgZm9yIHRoZSBVU0EgZGF0YQogIGdlb21fdGV4dChkYXRhPXN1YnNldChCTUlfZGlmZl9sb25nICU+JSAKICAgIGZpbHRlcihTZXggJWluJSBjKCJNZW4iLCAiV29tZW4iKSwKICAgICAgICAgICBUeXBlICE9ICJOYXRpb25hbCIpLCAKICAgICAgICAgICBDb3VudHJ5ID09ICJVU0EiKSwKICAgIGFlcyh4ID1UeXBlLCB5ID1EaWZmZXJlbmNlLGxhYmVsPUNvdW50cnkpLCAKICAgIGNvbG9yID0gImJsYWNrIikgKyAKICAjIFRoaXMgd2lsbCBhZGQgVVNBIGxhYmVscyB0byB0aGUgVVNBIHBvaW50cwogIHRoZW1lX2xpbmVkcmF3KCkgKwogICAgIyBUaGlzIHdpbGwgbWFrZSB0aGUgYmFja2dyb3VuZCBvZiB0aGUgcGxvdCB3aGl0ZSBhbmQgdGhlIGZhY2V0IGxhYmVscyBibGFjawogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgCiAgIyBUaGlzIGlzIHVzZWZ1bCBmb3IgcmVtb3ZpbmcgdGhlIGxlZ2VuZAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSxhbmdsZSA9IDMwLCB2anVzdCA9IDAuNSksIAogICAgICAgICMgdGhpcyBjaGFuZ2VzIHRoZSBzaXplIGFuZCBhbmdsZSBvZiB0aGUgeCBheGlzIHBvaW50IGxhYmVscyAKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLCAKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9MTUpLCAKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9MTUpLCAKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSkKICAjIHRoaXMgY2hhbmdlcyB0aGUgc2l6ZSBvZiB4IGF4aXMgbGFiZWxzIGZvciB0aGUgZmFjZXQKCiNhZGQgbGFiZWxzCkRpZmZfcGxvdDwtRGlmZl9wbG90ICsgCiAgICAgICAgbGFicyh0aXRsZSA9ICJDaGFuZ2UgaW4gQk1JIGJ5IHJlZ2lvbiIsIAogICAgICAgICAgICAgeCA9ICIiLCAKICAgICAgICAgICAgIHkgPSAiQ2hhbmdlIGluIEJNSSBcbiAoMTk4NSB0byAyMDE3KSIpICsKICAgICAgICB0aGVtZSh0aXRsZSA9IGVsZW1lbnRfdGV4dCAoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSkKCk1lYW5zX3Bsb3QgPC1NZWFuc19wbG90ICsgCiAgICAgICAgbGFicyh0aXRsZSA9ICJNZWFuIEJNSSBvdmVyIHRpbWUiLCAKICAgICAgICAgICAgIHggPSAiIiwgCiAgICAgICAgICAgICB5ID0gIk1lYW4gQk1JIikgKwogICAgICAgIHRoZW1lKHRpdGxlID0gZWxlbWVudF90ZXh0IChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpKQoKCgpvYmVzaXR5X3RleHQ8LXRpYmJsZShZZWFyPWMoMTk4NSksQk1JPWMoMzEpLFNleD1jKCJNZW4iKSxsYWJlbD1jKCJPYmVzaXR5IikpCgpNZWFuc19wbG90IDwtTWVhbnNfcGxvdCArIAogICAgICAgICAgICAgZ2VvbV90ZXh0KGRhdGEgPSBvYmVzaXR5X3RleHQsCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9cHVsbChvYmVzaXR5X3RleHQsbGFiZWwpLCAKICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICBhZXMoIGZvbnRmYWNlID0iYm9sZC5pdGFsaWMiLCBzaXplID0gMTMpKQoKY293cGxvdDo6cGxvdF9ncmlkKE1lYW5zX3Bsb3QsIERpZmZfcGxvdCwgbGFiZWxzID0gYygiQSIsICJCIikpCgoKYGBgCgpHcmVhdCwgbm93IHdlIGhhdmUgcHV0IHR3byBwbG90cyB0b2dldGhlciB1c2luZyB0aGUgYHBsb3RfZ3JpZCgpYCBmdW5jdGlvbiBvZiB0aGUgYGNvd3Bsb3RgIHBhY2thZ2UuIFRoaXMgd2F5IHdlIGNhbiBjbGVhcmx5IGNvbW11bmljYXRlIHR3byBtZXNzYWdlcy4gVGhlIGZpcnN0IGJlaW5nIHRoYXQgQk1JIGhhcyBpbmNyZWFzZWQgb3ZlciB0aW1lIGdsb2JhbGx5IGFuZCB0aGF0IG1hbnkgY291bnRyaWVzIGluY2x1ZGluZyB0aGUgVW5pdGVkIFN0YXRlcyBvZiBBbWVyaWNhIGFyZSBhcHByb2FjaGluZyBhIG1lYW4gQk1JIHRoYXQgaXMgYWJvdmUgdGhlIG9iZXNpdHkgdGhyZXNob2xkIG9mIDMwLiBXZSBjYW4gYWxzbyBzZWUgdGhhdCB3b21lbiBvbiBhdmVyYWdlIGhhdmUgbGFyZ2VyIEJNSSB2YWx1ZXMgdGhhbiBtYWxlcywgYnV0IHRoYXQgYm90aCBnZW5kZXJzIHNob3cgaW5jcmVhc2VkIGxldmVscyBvdmVyIHRpbWUuIEluIHRoZSBzZWNvbmQgcGxvdCB3ZSBjYW4gc2VlIHRoYXQgdGhlIGluY3JlYXNlIGluIEJNSSBpcyBub3QganVzdCBoYXBwZW5pbmcgaW4gIHVyYmFuIGNvbW11bml0aWVzLCBidXQgaW4gYm90aCBydXJhbCBhbmQgdXJiYW4gY29tbXVuaXRpZXMgYW5kIHBhcnRpY3VsYXJseSBpbiB3b21lbi4gCgojIyBTdW1tYXJ5CgpXZSBoYXZlIGV2YWx1YXRlZCBCTUkgYXZlcmFnZSBlc3RpbWF0ZXMgZnJvbSAyMDAgZGlmZmVyZW50IGNvdW50cmllcyBhcm91bmQgdGhlIHdvcmxkLiBUbyBkbyBzbyB3ZSBpbXBvcnRlZCBkYXRhIGZyb20gYSBwZGYgdXNpbmcgdGhlIGBwZGZ0b29sc2AgcGFja2FnZS4gV2UgdXNlZCBgdGlkeXZlcnNlYCBwYWNrYWdlcyBzdWNoIGFzIGBkcGx5cmAsIGBzdHJpbmdyYCwgYW5kIGB0aWR5YCB0byBjbGVhbiB0aGUgZGF0YSBhbmQgZ2V0IGl0IGluIGEgd29ya2FibGUgZm9ybWF0LiBPdXIgc3RhdGlzdGljYWwgYW5hbHlzaXMgZm9jdXNlZCBvbiBldmFsdWF0aW5nIGRpZmZlcmVuY2VzIGluIEJNSSBpbiBmZW1hbGVzIGFyb3VuZCB0aGUgd29ybGQgYWNyb3NzIHRpbWUgYW5kIGJldHdlZW4gcnVyYWwgYW5kIHVyYmFuIGFyZWFzLiBXZSBmb3VuZCBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgYm90aCBiZXR3ZWVuIHllYXJzIGFuZCBiZXR3ZWVuIHRoZSB0eXBlIG9mIGNvbW11bml0eSBhbW9uZyB3b21lbiBnbG9iYWxseSB1c2luZyB0LXRlc3RzIGFuZCBub25wYXJhbWV0cmljIHRlc3RzLiBUaHVzIEJNSSBoYXMgaW5jcmVhc2VkIGluIHdvbWVuIHNpbmNlIDE5ODUuIEFsdGhvdWdoIEJNSSBlc3RpbWF0ZXMgYXJlIHNpZ25pZmljYW50bHkgaGlnaGVyIGluIFVyYmFuIGFyZWFzIGNvbXBhcmVkIHRvIHJ1cmFsIGFyZWFzLCBCTUkgZXN0aW1hdGVzIGhhdmUgaW5jcmVhc2VkIGluIGJvdGggcmVnaW9ucy4gV2UgbGVhcm5lZCB0aGF0IHRoZXJlIGFyZSBhc3N1bXB0aW9ucyBhbmQgY29uc2lkZXJhdGlvbnMgdG8ga2VlcCBpbiBtaW5kIHdoZW4gcGVyZm9ybWluZyB0ZXN0cyB0aGF0IGNvbXBhcmUgdHdvIGdyb3Vwcy4gCgo8dT4gV2UgbGVhcm5lZCB0aGF0IHRoZSB0LXRlc3QgcmVsaWVzIG9uOjwvdT4KMSkgbm9ybWFsaXR5IG9mIHRoZSBkYXRhIGZvciBib3RoIGdyb3VwcyAodGhpcyBpcyBub3QgYXMgbXVjaCBvZiBhbiBpc3N1ZSBpZiB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpcyByZWxhdGl2ZWx5IGxhcmdlIHRvdGFsIG4+MzApCjIpIGVxdWFsIHZhcmlhbmNlIGJldHdlZW4gdGhlIHR3byBncm91cHMgKG1ha2Ugc3VyZSB5b3UgZG8gdGhlIGNvcnJlY3QgdGVzdCBpZiB0aGUgZGF0YSBpcyBub3Qgbm9ybWFsKQozKSBiYWxhbmNlZCBzYW1wbGUgc2l6ZXMgb2YgdGhlIHR3byBncm91cHMKCldlIGxlYXJuZWQgdGhhdCB3ZSBjYW4gZXZhbHVhdGUgaWYgb3VyIGRhdGEgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgYnkgcGxvdHRpbmcgdGhlIGRpc3RyaWJ1dGlvbiBhbmQgYnkgY3JlYXRpbmcgUS1RIHBsb3RzLgoKPHU+V2UgbGVhcm5lZCB0aGF0IGlmIG91ciBkYXRhIGlzIG5vdCBub3JtYWxseSBkaXN0cmlidXRlZCwgd2UgY2FuIGNvbnNpZGVyIHRoZXNlIG9wdGlvbnM6PC91PgoxKSBXZSBjYW4gc3RpbGwgcGVyZm9ybSBhIHQtdGVzdCBpZiBvdXIgbiBpcyBsYXJnZQoyKSBXZSBjYW4gdHJhbnNmb3JtIHRoZSBkYXRhIGJlZm9yZSBwZXJmb3JtaW5nIGEgdC10ZXN0CjMpIFdlIGNhbiB1c2UgYSBub25wYXJhbWV0cmljIHRlc3QgKFdpbGNveG9uIHNpZ25lZCByYW5rIHRlc3QgYW5kIHRoZSBUd28tc2FtcGxlIEtvbG1vZ29yb3YtU21pcm5vdiAoS1MpIHRlc3QpCgpXZSBsZWFybmVkIHRoYXQgaWYgb3VyIGdyb3VwcyBkbyBub3QgaGF2ZSBlcXVhbCB2YXJpYW5jZSwgdGhhdCB3ZSBuZWVkIHRvIHVzZSBhIG1vZGlmaWVkIHQtdGVzdCB0byBhY2NvdW50IGZvciB0aGlzIG9yIHRoZSBjb3JyZWN0IG5vbnBhcmFtZXRyaWMgdGVzdCB0aGF0IGRvZXMgbm90IHJlbHkgb24gdGhpcyBhc3N1bXB0aW9uIChUd28tc2FtcGxlIEtvbG1vZ29yb3YtU21pcm5vdiB0ZXN0KS4KCldlIGFsc28gbGVhcm5lZCB0aGF0IGlmIG91ciBncm91cHMgYXJlIG5vdCB3ZWxsIGJhbGFuY2VkLCB0aGF0IHdlIGNhbiBjb25zaWRlciByZXNhbXBsaW5nIG1ldGhvZHMuCgpGaW5hbGx5IGl0cyBhbHNvIGltcG9ydGFudCB0byByZW1lbWJlciB0aGF0IHdoZW4gd2UgaGF2ZSBbcGFpcmVkIGRhdGFdKGh0dHBzOi8vd3d3LnN0YXRpc3RpY3Nob3d0by5kYXRhc2NpZW5jZWNlbnRyYWwuY29tL3BhaXJlZC1kYXRhLykgYW5kIGludGVuZCB0byBjb21wYXJlIG1lYW5zLCB3ZSBzaG91bGQgcGVyZm9ybSBhIHBhaXJlZCB0ZXN0IChwYWlyZWQgdC10ZXN0LCBXaWxjb3hvbiBzaWduZWQgcmFuayB0ZXN0LCBvciBwYWlyZWQgS1MgdGVzdCkuIE91ciBkYXRhIHVzZWQgaW4gdGhpcyBjYXNlIHN0dWR5IHdhcyBwYWlyZWQgYmVjYXVzZSBvYnNlcnZhdGlvbnMgd2VyZSB0YWtlbiBmb3IgdGhlIHNhbWUgY291bnRyaWVzIGZvciBkaWZmZXJlbnQgY2F0ZWdvcmllcyBvZiBwb3B1bGF0aW9ucyAtIHRodXMsIHdlIHdhbnRlZCB0byBjb21wYXJlIHRoZXNlIHBvcHVsYXRpb25zIHdpdGhpbiB0aGUgc2FtZSBjb3VudHJ5IChtYWxlIHZzIGZlbWFsZSwgcnVyYWwgdnMgdXJiYW4gZXRjLikuIE90aGVyIGV4YW1wbGVzIHdvdWxkIGJlIGluIGEgY2FzZS1jb250cm9sIHN0dWR5IChpZiBzYW1wbGVzIGFyZSBtYXRjaGVkIGZvciB2YXJpb3VzIGRlbW9ncmFwaGljcykgb3IgYSBzdHVkeSB3aXRoIHJlcGVhdGVkIG1lYXN1cmVzIChmb3IgZXhhbXBsZSwgc3ltcHRvbSBtZWFzdXJlcyBmcm9tIHRoZSBzYW1lIGluZGl2aWR1YWwgYmVmb3JlIGFuZCBhZnRlciBhIHRyZWF0bWVudCkuIAoKClVzaW5nIHRoZSBgZ2dwbG90MmAgcGFja2FnZSB3ZSB3ZXJlIGFibGUgdG8gdmlzdWFsaXplIHRyZW5kcyBpbiB0aGUgZGF0YS4gSW1wb3J0YW50bHksIHRoZSBsYXJnZXN0IGluY3JlYXNlIGFwcGVhcnMgdG8gYmUgaW4gdGhlIHJ1cmFsIGFyZWFzIHBhcnRpY3VsYXJseSBmb3Igd29tZW4uIFdlIHdlcmUgYWxzbyBhYmxlIHRvIGlkZW50aWZ5IGhvdyB0aGUgVVMgY29tcGFyZWQgdG8gb3RoZXIgY291bnRyaWVzIGFuZCB3aGljaCBjb3VudHJpZXMgc2hvd2VkIHRoZSBsYXJnZXN0IGluY3JlYXNlIGluIEJNSSBvdmVyIHRpbWUuIEFuYWx5c2VzIGxpa2UgdGhpcyBhcmUgaW1wb3J0YW50IGZvciBkZWZpbmluZyB3aGljaCBncm91cHMgY291bGQgYmVuZWZpdCB0aGUgbW9zdCBmcm9tIGludGVydmVudGlvbnMsIGVkdWNhdGlvbiwgYW5kIHBvbGljeSBjaGFuZ2VzIHdoZW4gYXR0ZW1wdGluZyB0byBtaXRpZ2F0ZSBwdWJsaWMgaGVhbHRoIGNoYWxsZW5nZXMuIFlvdSBjYW4gc2VlIGluIHRoZSBbYXJ0aWNsZV0oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9zNDE1ODYtMDE5LTExNzEteC5wZGYpIHRoYXQgdGhpcyBkYXRhIGNhbWUgZnJvbSB0aGF0IG1hbnkgYWRkaXRpb25hbCBjb25zaWRlcmF0aW9ucyB3b3VsZCBiZSBpbnZvbHZlZCB0byBwZXJmb3JtIHN1Y2ggYW4gYW5hbHlzaXMuCgoKIyMjIFN1Z2dlc3RlZCBIb21ld29yawoKU3R1ZGVudHMgY2FuIGV2YWx1YXRlIHRoZSBjaGFuZ2UgaW4gQk1JIG92ZXIgdGltZSB1c2luZyB0aGUgZ2xvYmFsIGRhdGEgYXZhaWxhYmxlIGZvciBlYWNoIHllYXIgYmV0d2VlbiAyMDE1IGFuZCAyMDE3LiBUaGlzIGRhdGEgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwOi8vd3d3Lm5jZHJpc2Mub3JnL2Rvd25sb2Fkcy9ibWkvTkNEX1Jpc0NfTGFuY2V0XzIwMTdfQk1JX2FnZV9zdGFuZGFyZGlzZWRfd29ybGQuY3N2KS4K